اگر مجبورید کلاسی را با آمدن یک ویژگی جدید تغییر دهید، ممکن است اصل SRP را نقض کرده باشید. به طور معمول، هر زمان که شما نیاز به پیاده سازی cross-cutting concerns ها مانند logging، caching و غیره داشته باشید، این اتفاق می افتد.
ما با ایجاد دو کلاس مجزا refactoring را انجام دادیم. یکی برای تزئین (decorate) دیگری استفاده می شود. توجه داشته باشید که همچنین یک اینترفیس را استخراج و کلاس decorator نمونه ای از اینترفیس را به عنوان یک وابستگی در نظر میگیریم. به همین راحتی می توانید یک کلاس را تزئین (decorate) کنید.
میبینید که UserRepository چقدر ساده است، و حالا فقط یک مسئولیت دارد؟ Logging دیگر نگرانی نیست.ما یک کلاس UserRepositoryLoggingDecorator جداگانه ایجاد کردهایم که از logging مراقبت میکند.
این اصل مورد علاقه من است. اینکه بتوانید فقط کلاس های جدید را اضافه کنید و کلاس های موجود را لمس نکنید، بسیار عالی است.
شما به سرعت نقض OC را تشخیص می دهید. هر ویژگی جدید نیاز به یک if جدید دارد. درست مانند کلاس ProductFormatter، که یک نوع product را میگیرد و رشتهای را که به روشی دلخواه قالببندی شده است را برمیگرداند.
در ابتدا خیلی بد به نظر نمی رسد.با این حال، برای هر نوع قالب بندی جدید، شما باید OCP را زیر پا بگذارید. همچنین، اگر اشکالی وجود دارد و باید منطق قالب بندی را اصلاح کنید، باید این کار را در جایی که توسط کد غیر مرتبط احاطه شدهاست انجام دهید.
استفاده از polymorphism برای حذف if-else دیوانه کننده و غیر ضروری، یکی از بهترین و آسانترین روشها است. به این ترتیب، شما به اصل Substitution Liskov دست میزنید. اکنون، ما کد غیرقابل انعطاف بالا را refactor کرده ایم.
بنابراین، شما به وضوح متوجه شده اید که اکنون چقدر کد بیشتری وجود دارد. Refactoring به معنای کوچک کردن کد نیست، بلکه در مورد ایجاد کدهایی است آسانتر که با عقل و منطق کنار بیاید.
ابتدا هر تکه منطقی را داخل if و else-if قرار می دهیم و آن را در داخل کلاس formatter قرار دهیم. اکنون هر کلاس یک هدف واحد دارد. زمانی که شما نیاز به رفع یک باگ دارید، می دانید که تمام کدهای اطراف به آن مربوط می شود.
ثانیاً، هر formatter با فراخوانی RegisterFormatter آن در ProductFormatter فراخوانی میشود.
پیادهسازی Format در حالی که خود قالببندی را کنترل میکند، برای استفاده از جستجوی formatter تغییر داده شدهاست.همچنین، توجه داشته باشید که اکنون یک JSON formatter وجود دارد. که به سادگی با اضافه کردن یک کلاس برای آن مدیریت می شود.
در اینجا مثالی از نحوه استفاده از product formatter آورده شده است.
شما احتمالاً از کلاس های استفاده کرده اید یا حتی ساخته اید که مشابه چاقوی سوئیسی عمل می کنند.به اندازه کافی عمومی برای هر چیزی. آنها اساساً بدردنخور هستند.
فرض کنید ما یک کلاس داریم که برای به روز رسانی یک کاربر استفاده می شود. این کلاس به یک UserManager وابسته است که شامل مهم ترین و اصولی ترین ویژگی های یک چیز است.
همه چیز عالی است اما، ما می توانیم بهتر عمل کنیم.در حال حاضر، کلاس UpdateUser می تواند آزادانه به هر روشی که توسط user manager در معرض نمایش قرار می گیرد دسترسی داشته باشد. دقیقاً آن چیزی نیست که ما می خواهیم، درست است؟
ما با یک ابزار تک منظوره مانند آنچه در قسمت پایین آمده، وابستگی به چاقو سوئیسی را عوض میکنیم.توجه کنید که چگونه UpdateUserCommand و UserManager تقریباً بدون تغییر باقی مانده است.پاک کردن کدهای کثیف به همین سادگی است.
شما قبلاً در این مقاله با اصل وارونگی وابستگی آشنا شده اید. همه چیز در مورد تکیه کردن به انتزاعی در کلاس های concrete است. بنابراین، کلاس زیر چندین اصل را نقض می کند. وابستگی خود به AppDatabase را «new» می کند.
بهجای «new» کردن در نمونههای عینی، آنها را بهعنوان وابستگیهای صریح و روشن در نظر میگیرید، و میخواهید به جای یک کلاس مشخص، بر انتزاع تکیه کنید. به بیان ساده، شما می خواهید یک interface را به عنوان آرگومان سازنده در نظر بگیرید.
به این کلاس GetUsersCommand بهبود یافته نگاهی بیندازید.«new» کردن کلاس ها را متوقف کنید و interface ها را به عنوان آرگومان های سازنده در نظر بگیرید. انصافاً به همین سادگی است.
"تعداد کلاس ها با هر refactor که شما انجام می دهید افزایش می یابد!"
این ممکن است یکی از اعتراضات شما به رویکرد refactoring باشد. به یاد داشته باشید که refactoring به معنای کوچک کردن کد یا حتی لزوماً سادهتر کردن همه چیز نیست. این در مورد تغییر کد شما برای مطابقت با پیچیدگی برنامه و تسهیل کار با کد است.
متن فوق برگرفته شده از مدیوم Nicklas Millard می باشد