طراحی شی گرا - اصول SOLID گام دوم - SRP و OCP

توی قسمت اول درباره لزوم استفاده ازدیزاین پترن ها و مفاهیم اولیه طراحی شی گرا صحبت کردیم. توی این قسمت می خوایم تا در مورد دو مفهموم Single Responsibility و Open-closed از اصول SOLID صحبت کنیم.اصل اول Single Responsibility Principle (SRP)این اصل به ما میگه که هر ماژول، کلاس یا متد در برنامه ما باید تنها یک مسئولیت داشته باشه و فقط یک کار مشخص رو انجام بده. مثلا اگر قراره فرآیند ثبت نام و ورود کاربر به وب سایتمون رو پیاده سازی کنیم طراحی درست استفاده از دو کلاس یا دو متد جداگانه برای هرکدوم از این فرآیندهاست.حالا چطور این اصل رو رعایت کنیم؟برای رعایت اصل single responsibility باید تا حد امکان کلاس ها ومتدهامون رو به فرآیندهای جداگانه بشکنیم.برای مثال در فرآیند خرید باید دو کلاس جداگانه برای خرید در محل و خرید آنلاین داشته باشیم و انجام دادن این دو فرآیند از طریق یک کلاس خرید کار درستی نیست! علاوه براین بهتره تا جاهایی که در این کلاس ها وابسته به یک سرویس خارجی هستیم مثل درگاه بانکی یا پرداخت از طریق دستگاه کارتخوان، را بااستفاده از interface های جداگانه پیاده سازی کنیم.نکته جانبی: بهتره خروجی تمام متدهایی که از یک جنس هستند مثل پرداخت کارت به کارت، کارتخوان یا درگاه بانکی به یک شکل باشه یا به عبارت دیگه از یک template مشترک استفاده کنن.با استفاده از این اصل ما سعی می کنیم تا جاهایی از برنامه رو که احتمال تغییر در اون ها زیاده شناسایی کنیم و اون بخش ها رو با استفاده از Abstraction وInterface های مورد نیاز پیاده سازی کنیم.تنها یک دلیل برای تغییر یک کلاس و یا یک متد باید وجود داشته باشد.Robert C Martinاصل دوم Open-Closed Principle (OCP)در یک جمله یعنی قابلیت افزودن featureهای جدید بدون ایجاد تغییر در کلاس ها و متدهای قبلی وجود داشته باشه. در واقع ما باید ازایجاد شدن تغییرات آبشاری توی سیستم جلوگیری کنیم! یکم تخصصی تر بگیم میشه:open for new features and close for changesطراحی ما در حالت ایده آل طوری جلو میره که برای اضافه کردن قابلیت ها و ویژگی های جدید به سیستم فقط کافیه یک کلاس و یا یک متد جدید بنویسیم بدون اینکه به روندهای موجود دست بزنیم. اگر با اضافه کردن ویژگی یا feature جدید به سیستم مجبور شدیم به کدهای قبلی امون دست بزنیم یعنی یه جای کار می لنگه!معمولا قسمت هایی از کد که if/else کنار هم زیاده استفاده شده نشونه اینه که باید اون قسمت رو با رعایت اصل open-closed بازنویسی یا در اصطلاح refactor کنیم.حالا چطور باید OCP رو در کدهامون پیاده سازی کنیم؟بااستفاده از پارامترهای کنترلی در متدهااستفاده از inheritance (دیزاین پترن template اینجا می تونه مفید باشه.)استفاده از composition (دیزاین پترن strategy اینجا می تونه مفید باشه.)علاوه بر دیزاین پترن هایی که بالا بهشون اشاره کردیم دیزاین پترن های Factory و Builder هم اینجا می تونن مفید و کاربردی باشن.برای روشن تر شدن موضوع بیاید فرض کنیم که ما درحال پیاده سازی یک درگاه پرداخت در محصولمون هستیم. حالا با توجه به اینکه کاربر چه نوع پرداختی رو انتخاب میکنه چندتا if نوشتیم که اگر از نوع پرداخت آنلاین بود برو متد online_payment رو صدا بزن، اگر از نوع پرداخت کارت به کارت بود برو متد cart_to_cart رو صدا بزن و اگر از نوع پرداخت در محل بود متد local_payment رو صدا بزن.اما OCP چی میگه؟میگه شما بیا یه کلاس پرداخت به صورت abstract پیاده سازی کن و ۳ تا کلاس برای هرکدوم از انواع پرداخت. این کلاس ها متد pay رو از والد خودشون (که همون کلاس Payment هست) به ارث میبرن و هرکدوم به شیوه خودشون اون رو override میکنن. اینجوری دیگه اون if/else ها از برنامه حذف میشه و شما هنگام پرداخت کاربر فقط کافیه متد pay رو برای اون object صدا بزنی.برای دیدن یه مثال دیگه از پیاده سازی این اصل می تونید به انتهای این لینک سر بزنید.