آموزش جامع دیزاین پترن (Design pattern) ها در کاتلین
اگر شما اینجا هستید و باری، قبلاً درباره نام کاتلین شنیده اید. در این مقاله ابتدا در یکی دو بند به مرور خلاصه ای دربارۀ آنکه کاتلین چه مزیت های هایی دارد می کنیم و در ادامه به صورت جامع دربارۀ چیستی دیزاین پترن ها در کاتلین سخن به میان خواهیم آورد. همچنین در آینده به ازای هر کدام از دیزاین پترن ها در کاتلین یک مقاله جامع در سایت خواهیم نگاشت.
لازم است با مفاهیم شئ گرایی و اصطلاحاتی مانند نمونه سازی(به معنی ایجاد یک شئ جدید از کلاس) ازپیش آشنایی داشته باشید.
چگونه کاتلین نسبت به جاوا، روش های ساده تری را برای نوشتن کدها فراهم کرده است؟
بچه های شرکت نامیِ jetBrains از جاوا استفاده می کردند و این زبان در آن زمان بهره وری آنها را کاهش می داد. بدین دلیل برای آسانی کارهایشان زبان برنامه نویسی کاتلین را ساختند؛ یک زبان برنامه نویسی متن باز و تایپ ایستا.
درواقع همانطور که جیمز گاسلینگ سازندۀ زبان برنامه نویسی جاوا از کد زدن با C++ خسته شد و زبان جاوا را ساخت؛ دوستان ما هم از کد زدن با جاوا خسته شدند و زبان کاتلین را که امکانات تازه ای داشت و معایب جاوا را برطرف کرده بود، ساختند.
کاتلین یک زبان برنامه نویسی شئ گرا است که از امکانات برنامه نویسی functional در کنار شئ گرایی استفاده می کند و به همین دلیل است شما می توانید function ها را آزادانه بدونه آنکه درون wrapper هایی مانند class و interface باشند درون یک فایل خالی بنویسید.
اما جاوا صرفا یک زبان برنامه نویسی شئ گرا است و اگر یک function را بدون آنکه درون یک wrapper ای مانند class یا interface، درون یک فایل خالی بنویسید به خطا خواهید خورد.
پس قطع به یقین سازندگان کاتلین با این قبیل تفکرات خلاقانه که بررسیِ کوتاه همۀ آنها که خود یک یا چند مقالۀ مفصل را می طلبد؛ برای پیاده سازی دیزاین پترن ها هم نسبت به جاوا دست به شگفتانه هایی باید زده باشند.
دیزاین پترن (Design pattern) یا الگوی طراحی چیست؟
توسعه نرم افزار مستلزم خلاقیت و تفکر خارج از چهارچوب است زیرا شما اغلب با مشکلات پیچیده ای مواجه هستید که نیاز به راه حل های منحصر به فرد دارد.
اما لازم نیست هربار که مشکلی را حل می کنید چرخ را از اول اختراع کنید؛ و اینجا است که سخن از دیزاین پترن ها به میان می آید.
در جهان طراحی نرم افزار، شما اغلب به وضعیت هایی بر می خورید که پیشتر دیگران بدان ها برخورده بودند. خوشبختانه، ما اکنون راه حل های قابل استفاده مجدد برای این مشکلات تکراری را داریم: دیزاین پترن ها!
این الگو (pattern) ها قبلاً استفاده و آزموده شده اند. تنها کاری که باید انجام دهید آنست که مشکلتان را به وضوح درک کنید تا یک دیزاین پترن (Design pattern) یا الگوی طراحی مناسب را که متناسب با نیازهای شما باشد شناسایی کنید.
انواع دیزاین پترن ها (الگوهای طراحی) در کاتلین
ما دیزاین پترن ها را به سه دستۀ اصلی Creational و Structural و Behavioral دسته بندی می کنیم؛ که هرکدام از این دسته ها به یک مسئله ای متفاوت دربارۀ class های ما و آنکه چگونه می توان از دیزاین پترن ها برای آن استفاده کرد پاسخ می دهد.
ما به صورت ژرف دربارۀ تک تک دیزاین پترن هایی که باید بدانید جداگانه سخن خواهیم گفت و در زنجیره ای از مقالات که توسط این جانب نگاشته می گردد؛ به ازای هر دیزاین پترن (الگوی طراحی) یک مقاله خواهیم داشت.
الگوهای طراحی بسیارند اما به طور کلی 26 تای آنها اصلی هستند ولی شما باید دیزاین پترن های دیگر را هم که در کاتلین بکار رفته اند و دانستن آنها ضروریست را بدانید، مانند الگوهای طراحی Delegation و Injection. دربارۀ دیزاین پترن های فرعی هم در آینده اطلاعات ارزنده ای در اختیار شما می گذاریم.
در ادامۀ این مقاله می خواهیم یاد بگیریم چگونه با استفاده از ویژگی های کاتلین می توان دیزاین پترن ها را پیاده سازی کرد. همچنین مروری کوتاه دربارۀ چند دیزاین پترن نامی، از هرکدام از سه دستۀ اصلی دیزاین پترن ها خواهیم داشت.
توجه داشته باشید الگوهای طراحی (Design patterns) الزاما برای توسعه نرم افزار هایی که با جاوا و کاتلین و … می نویسیم بکار نمی روند. حتی خود زبان های برنامه نویسی هم توسط دیزاین پترن ها ساخته شده اند.
برای مثال مفهوم ارث بری در زبان های برنامه نویسی از دیزاین پترن Injection ریشه گرفته است.
دیزاین پترن (Design pattern) های Creational چیستند؟
همانطور که از نام آن پیداست، الگو های این دسته بر نحوۀ ایجاد Object ها تمرکز دارند. استفاده از چنین الگوهایی باعث می شود کد ما انعطاف پذیر و قابل استفادۀ مجدد باشند.
تعریف: کلاس غیر انتزاعی یا concrete، کلاسی است که انتزاعی نیست و هیچ تابع انتزاعی درون خود ندارد که هنگام ساخت شئ از آن مجبور شویم از کلاس بی نام استفاده کنیم.
در مهندسی نرم افزار، الگو های طراحی Creational (ایجاد کننده)، الگوهای طراحی ای هستند که با سازوکار های ایجاد شئ سروکار دارند. آنها تلاش می کنند اشیاء را با شیوه ای مناسب با موقعیت ایجاد کنند.
شکل اصلی ایجاد شئ (که برای مثال در کاتلین برای کلاس MyClass، به صورت MyReponse()
می باشد) می تواند منجر به مشکلات طراحی یا افزودن پیچیدگی به طراحی شود.
الگوهای طراحی Creational این مشکل را از طریق کنترل ایجاد اشیاء حل می کنند.
دیزاین پترن های Creational از دو ایدۀ غالب تشکیل شده اند:
- اطلاعات پیرامون آنکه کدام کلاس غیر انتزاعی توسط سیستم استفاده می شود را کپسوله سازی(پنهان) می کند.
- نهان سازی آنکه چگونه نمونه های کلاس غیر انتزاعی مذکور، ایجاد و با هم ترکیب می شوند.
دیزاین پترن های Creational اغلب به دو دستۀ الگوهای Object-creational و Class-creational دسته بندی می شوند.
الگوهای Object-creational با ساخت شئ سروکار دارند و الگوهای Class-creational با نمونه سازی از کلاس ها سر و کار دارند.
به طور جزئی تر، الگوهای Object-creational بخشی از ایجاد شئ خود را به یک شئ دیگر واگذار می کنند؛ درحالی که الگوهای Class-creational ، شئ سازیِ خود را به زیر کلاس ها واگذاری می کنند.
پنج دیزاین پترن (الگوی طراحی) نامی، در زیر فهرست شده است:
- Abstract factory pattern، که یک interface برای ایجاد اشیای مرتبط به هم یا وابسته به هم، بدون تعیین کردن اشیای کلاس های غیر انتزاعی
- Builder pattern، که ساخت یک شئ پیچیده را از کد آن جدا می کند تا فرآیند ساخت شئ یکسان کد متفاوتی را ایجاد کند.
- Factory method، که به یک کلاس اجازه می دهد تا نمونه سازی را به زیرکلاس ها واگذار کند.
- Prototype، که نوع شئ را برای ایجاد کردن با استفاده از نمونۀ اولیه (Object اولیه) مشخص می کند و با شبیه سازی کردن این نمونۀ اولیه اشیاء جدیدی را می سازد.
- Singleton، که تضمین می کند که یک کلاس فقط یک نمونه دارد و یک نطقۀ دسترسی جهانی (Global) به آن فراهم می کند.
دیزاین پترن Injection که نام کامل آن Dependency Injection هست و به معنای تزریق وابستگی می باشد نیز جزء همین دسته می باشد.
در ادامه مروری کوتاه بر چند تا از دیزاین پترن های Creational خواهیم داشت.
دیزاین پترن Builder
در برنامه نویسی اندروید ما زیاد با این دیزاین پترن سر و کله زده ایم.
برای مثال وقتی که شما از Retrofit استفاده می کنید نیاز به gsonBuilder برای ساخت gson خواهید داشت یا وقتی که از AlertDialog استفاده می کنید از Builder آن هم استفاده می کنید.
موقعی که از Room استفاده می کنید برای ایجاد نهایی Room از Builder استفاده می کنید و در آخر هم از تابع build()
برای ساخت نهایی Builder استفاده می کنید.
در این دیزاین پترن درج برخی از خصوصیات ساخت یک شئ اجباری هستند و برخی خصوصیات دیگر را می توان به صورت دل بخواهی درج کرد.
پس از اتمام کار می توان تابع build()
را صدا زد و باید بدانید تنها راه ساخت شئ بعلت private بود سازندۀ کلاس مورد نظر فقط همین الگوی طراحی می باشد پس نمی توان آن را دور زد.
val builder = AlertDialog.Builder(it) builder.setMessage(R.string.dialog_start_game) .setPositiveButton(R.string.start, DialogInterface.OnClickListener { dialog, id -> // Do Somthings }) .setNegativeButton(R.string.cancel, DialogInterface.OnClickListener { dialog, id -> // User cancelled the dialog }) // Create the AlertDialog object and return it builder.create()
کاتلین این دیزاین پترن را خیلی ساده پیاده سازی کرده است زیرا شما می توانید برای پارامتر های سازندۀ کلاس از قبل مقادیر پیش فرض استفاده کرده باشید. نیز هر property ای از سازندۀ کلاس مورد نظر را می توانید بدون ضرورت ترتیب با صدا زدن اسم آن مقدار دهی کنید.
MyResponse(DataState.SUCCESS, data = data)
در کد بالا سومین پارامتر سازندۀ کلاس ما data است و دومین پارامتر سازنده message از نوع رشته است و مقدار پیشفرض دارد، برای همین آن را جا گذاشتیم و مستقیما سومین پارامتر که data باشد را با ضدا زدن اسم آن و قرار دادن = ، مقدار دهی کردیم.
دیزاین پترن های Factory و Abstract Factory method یا Provider Model
این دو دیزاین پترن که عضو دستۀ Creational هستند شباهت هایی دارند. اما آنها متفاوت از هم پیاده سازی می شوند، همچنین موارد استفاده متمایز دارند.
الگوی Factory Method بر پایۀ تعریف توابع Abstract برای گام های پیاده سازی اولیۀ کلاس والد است(کلاس والد کلاسی است که کلاس فرزند از آن به ارث می برد).
در کاتلین این دیزاین پترن به زیر کلاس های منفرد (زیر کلاس نام دیگر کلاس فرزند است.) اجازه می دهد تا نحوۀ پیاده سازی اولیه و ایجاد آن ها را تعریف کنند.
می خوای به آخرین روش های برنامه نویسی اندروید و تمام معماری های رایجش مسلط بشی؟ اینجا رو یک نگاه بنداز
در مقایسه با سایر الگو(Pattern)های Creational مانند الگوی Builder، الگوی Factory Method نیازی به نوشتن یک کلاس جداگانه ندارد، اما فقط یک یا چند تابع اضافی حاوی منطق پیاده سازی اولیه نیاز دارد.
اگر یک مثال شناخته شده برای این دیزاین پترن بخواهیم بزنیم کلاس RecyclerView.Adapter
از اندروید است؛ بویژه تابع onCreateViewHolder()
که در آن است.
این تابع یک نمونه جدید از ViewHolder بر اساس محتوای عناصر List ای که محتوای RecyclerView ی شما را تامیین می کند، می سازد.
چنانکه در زیر نشان داده شده است:
class MyRecyclerViewAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { 0 -> HeaderViewHolder() 1 -> SeparatorViewHolder() else -> ContentViewHolder() } } }
در این مثال، تابع onCreateViewHolder()
در کلاس والد RecyclerView.Adapter
تعریف شده است که در نوبت خود در کلاس فرزند که برای پیاده سازی آداپتر بکار می رود بازنویسی می شود.
با ایجاد تابع Abstract در کلاس والد، آداپتر به کلاس های فرزند اش اجازه می دهد تا منطق پیاده سازی اولیه را بر اساس نیازهایشان برای ViewHolder های خود تعریف کنند.
از سوی دیگر، در کاتلین دیزاین پترن Abstract Factory Method که مانند دیزاین پترن Provider Model (که از سوی شرکت مایکروسافت ارائه شد) از یک کلاس ProviderBase استفاده می کند.
ProviderBase متکی بر ایجاد interface ای است که به خانواده ای از کلاس های نزدیک به هم اجازه می دهد نمونه سازی شوند.
یک مثال می تواند کارخانه ای باشد که قطعات خودرو را برای سازندگان گوناگون می سازد:
abstract class CarPartsFactory { fun buildEngine(/* engine parts */): Engine fun buildChassis(/* chassis materials */): Chassis } class CarPartsFactoryProvider { inline fun <reified M : Manufacturer> createFactory(): CarPartsFactory { return when (M::class) { Manufacturer.Audi -> AudiPartsFactory() Manufacturer.Toyota -> ToyotaPartsFactory() } } } class AudiPartsFactory: CarPartsFactory() { override fun buildEngine(...): AudiEngine override fun buildChassis(...): AudiChassis } class ToyotaPartsFactory: CarPartsFactory() { override fun buildEngine(...): ToyotaEngine override fun buildChassis(...): ToyotaChassis } // Usage: val factoryProvider = CarPartsFactoryProvider() val partsFactory = factoryProvider.createFactory<Manufacturer.Toyota>() val engine = partsFactory.buildEngine()
نکته: در بحث Generic ها حتما باید برای پارامتر های از نوع reified از inline استفاده کرد مطالعه بیشتر.
در این مثال interface به عنوان یک نقشه برای اینکه کارخانه های مستقل چه نوع قطعات خودرویی را باید بسازند و از چه سازه ها یا موادی (پارامتر ورودی) ساخته می شود درنگریسته می شود.
سپس این کارخانه ها(زیر کلاس ها) قطعات را بر اساس الزامات و فرآیند های خاص آن تولید کنندگان می سازند.
الگوی طراحی Singleton
دیزاین پترن Singleton شاید یکی از شناخته شده ترین دیزاین پترن ها باشد. بیشتر توسعه دهندگانی که با برنامه نویسی شئ گرا کار می کنند با این دیزاین پترن قبلاً کار کرده اند.
با این حال الگوی یاد شده یکی از مورد استفادۀ نادرست قرار گرفته ترین Design pattern های موجود است. ما در پایان این بخش دربارۀ چرایی آن گفتار خواهیم کرد.
این دیزاین پترن توسعه دهنده را قادر می سازد تا کلاسی را تعریف کند که تنها یک بار در کل پروژه ساخته شود و بیش از یک شئ نتوان از روی آن کلاس ساخت و تنها یک شئ از آن ساخته شود.
در هر جایی که از Singleton استفاده گردد؛ یگانه خواهد بود در واقع شما از آغاز تا پایان برنامه فقط یک شئ از کلاس خود خواهید داشت؛ بنابرین مصرف حافظه کاهش می یابد و ثبات تضمین می شود.
چه زمانی به دیزاین پترن Singleton نیاز خواهیم داشت؟
به طور کلی ما هنگامی از دیزاین پترن Singleton استفاده می کنیم که با برنامه های multi-threading (مانند ورود به سیستم، ذخیره سازی حافظه پنهان) سر و کار داشته باشیم.
بر اساس تعریف، یک کلاس singleton تنها یکبار نمونه سازی می گردد، یا به سرعت (در دمی که کلاس ایجاد می گردد) یا به صورت lazy و تنبلانه (در زمانی که برای اولین بار به آن کلاس دسترسی پیدا می شود).
دیزاین پترن Singleton می تواند موارد استفاده زیادی داشته باشد، مانند:
- حفظ یک حالت جهانی در یک سیستم
- پیاده سازی دیزاین پترن های دیگر مانند facade یا factory pattern متفاوت
- ارائه راهی ساده برای دسترسی به داده های جهانی
چرا دیزاین پترن Singleton به نادرست مورد استفاده قرار می گیرد؟
ما خیلی نمیخواهیم در این مقاله الگوی Singleton را موشکافی کنیم اما به طور کلی این دیزاین پترن نه تنها گاهی مورد استفادۀ نادرست قرار می گیرد بلکه در وهله های گوناگون حتی از آن به عنوان یک ضد الگو نام برده می شود. دلیل این امر این است که بیشتر مزایای آن را می تواند تبدیل به بزرگترین معایب آن بشوند.
برای مثال، این دیزاین پترن افزودن یک حالت جهانی (Global) به برنامه ها را بسیار آسان می کند، اما در صورت افزایش اندازۀ پایۀ کد، حفظ آن بسیار سخت خواهد بود.
افزون برین این واقعیت که می توان به آن در هر زمان دسترسی داشت، درک سلسله مراتب سیستم را بسیار دشوار می کند.
اگر وابستگیهای زیادی به متدها و زمینهها وجود داشته باشد، جابهجایی ساده برخی کلاسها یا تعویض یک پیادهسازی با دیگری میتواند به دردسر جدی تبدیل شود. در یک مقالۀ جداگانه دربارۀ الگوی Singleton این موضوع بیشتر باز شده است.
دیزاین پترن های Structural چیستند؟
در مهندسی نرم افزار، الگوهای طراحی Structural (ساختاری)، الگوهای طراحی هستند که با شناسایی یک راه ساده برای تحقق روابط بین موجودیت ها، طراحی را آسان می کنند.
الگوهای طراحی Structural برای پیوستاندن عملکرد های موجود هستند.
نمونه هایی از الگوهای ساختاری عبارتند از:
- Adapter : یک interface را برای یک class با interface مورد انتظار client تطبیق می دهد.
- Bridge : یک Abstract از پیاده سازی آن، جدا باید شود تا آن دو کاملا از یکدیگر مستقل باشند.
- Composite : ساختار درختی از اشیاء، که در آن هر شئ دارای interface یکسانی است.
- Decorator : در زمان اجرا هنگامی که زیرکلاس سازی به افزایش تصاعدی کلاس های جدید می فرجامد، تابع محوری بیشتر ایجاد کنیم.
- Facade : ایجاد یک interface ساده از یک interface موجود جهت آسانی استفاده برای کارهای رایج.
- Flyweight : تعداد زیادی از اشیاء برای صرفه جویی در فضای حافظه یک شئ از property های مشترک دارند.
- Proxy : کلاسی که به عنوان interface برای چیزی دیگر عمل می کند.
دیزاین پترن (Design pattern) های فرعی:
- Aggregate : یک نسخه از دیزاین پترن composite با توابعی برای تجمع فرزندان.
- Extensibility : همچنین به عنوان یک Framework شناخته می شود؛ کد های پیچیده را پشت یک interface ساده پنهان می کند.
- Pipes and filters : زنجیره ای از فرآیندها که در آن خروجی هر فرآیند ورودی فرآیند بعدی است.
- Private class data : محدود کردن دسترسی Getter و Setter در کلاس (accessor & mutator)
نیز دیزاین پترن Delegation هم جزء دسته دیزاین پترن های Structural می باشد.
نکتۀ اصلی دیزاین پترن های Structural (ساختاری) در ایجاد ساختارهای جدید بدون تخریب ساختارهای قدیمی نهفته است. افزون بر آن، استاندارد loose coupling (اتصال سست) برای استفادۀ مجدد و تغییر، هم در الگوهای ساختاری در عین محفوظ بودن افزایش هم یافته است.
ما به دیزاین پترن های Structural نیاز داریم زیرا ساختار های خاصی را در پروژه های خود تعریف خواهیم کرد. ما می خواهیم بتوانیم روابط بین کلاس ها و اشیاء را به درستی شناسایی کنیم تا آنها را به گونه ای بسازیم که ساختار پروژه را ساده کنیم.
دیزاین پترن های Adapter و Decorator و Facade، دیزاین پترن هایی از نوع Structural هستند که مروری کوتاه دربارۀ آنها در ادامه مقاله خواهیم داشت.
الگوی طراحی Adapter
نام این الگوی طراحی به همان وظیفه ای که انجام می دهد اشاره می کند: شکاف بین دو Interface ناسازگار را پر می کند و آنها را قادر می سازد تا با هم کار کنند، دقیقاً مانند آداپتوری که برای استفاده از شارژر تلفن آمریکایی در یک پریز ایرانی یا اروپایی استفاده می کنید.
در توسعۀ نرم افزار، زمانی که نیاز دارید برخی از داده ها را به فرمت دیگری تبدیل کنید، معمولا از یک آداپتور استفاده می کنید. برای مثال داده هایی که از backend دریافت می کنید ممکن است یک نمایش دیگری در repository شما برای Ui را بطلبد.
دیزاین پترن Adapter همچنین زمانی مفید است که شما باید عملیاتی را با استفاده از دو کلاس انجام دهید که به طور پیش فرض سازگار نیستند.
الگوی طراحی Decorator
الگوی طراحی Decorator نیز در دسته الگوهای طراحی Structural (ساختاری) قرار می گیرد زیرا به شما امکان می دهد رفتار های جدیدی را به یک کلاس موجود اختصاص دهید. باز هم، ما این کار را با ایجاد یک Wrapper یا لفاف که رفتارهای گفته شده را داشته باشد انجام می دهیم.
در مقالات آینده مفصل دربارۀ این الگو سخن خواهیم گفت.
الگوی طراحی Facade
هدف اصلی الگوی طراحی Facade فراهم کردن یک interface ساده تر و یکپارچه تر برای مجموعه ای از اجزای مرتبط است.
می توانیم از یک تشبیه مفید بکار ببریم: خودرو یک همداد پیچیده است که از صدها قسمت گوناگون تشکیل شده است که با هم کار می کنند.
اگرچه ما مستقیما با همۀ اجزای آن مستقیماً تعامل نمی کنیم اما فقط با تعداد انگشت شماری از قطعات که می توانیم از روی صندلی راننده به آنها دسترسی داشته باشیم: مانند پدال ها، چرخ ها، دکمه ها که به عنوان یک رابط کاربری ساده برای استفاده از ماشین عمل می کنند.
ما می توانیم همین اصل را در طراحی نرم افزار اعمال کنیم و اینجاست که الگوی طراحی Facade مطرح می شود.
Design Pattern های Behavioral چیستند؟
در مهندسی نرم افزار الگوهای طراحی Behavioral، الگوهای طرحی ای هستند که الگوهای ارتباطی مشترک بین شئ ها را شناسایی کرده و این الگوهای ارتباطی مشترک را تحقق می بخشند.
با انجام این کار، این الگوها انعطاف پذیری را در انجام این ارتباط افزایش می دهند.
الگوهای Behavioral بر چگونگی جریان حالت و رفتار در یک سیستم اثر می گذارند.
با بهینه سازی نحوۀ انتقال و تغییر حالت و رفتار در یک سیستم، می توانید قابلیت نگه داری یک برنامه را ساده، بهینه و افزایش دهید.
در فهرست زیر الگوهای رایج Behavioral (رفتاری) آمده اند:
- Responsibility : شئ های دستوری (Command Object) توسط شئ های پردازشیِ دارای منطق مدیریت می شوند یا به شئ های دیگر منتقل می شوند.
- Command : شئ های دستوری یک عمل و پارامترهای آن را کپسوله سازی (encapsulation) می کنند.
- Interpreter : پیاده سازی یک زبان کامپیوتری تخصصی برای حل سریع مجموعه ای از مشکلات.
- Iterator : Iterator (اشاره گر) ها برای دسترسی به عناصر یک مجموعه متوالی از شئ ها بدون ظاهر ساختن نمایش های زیرینِ آن.
- Mediator : یک interface یکپارچه برای مجموعه ای از interface ها در یک زیرسیستم فراهم می کند.
- Memento : امکان بازگرداندن یک شئ به حالت قبل اش را فراهم می کند.
- Observer : همچنین به نام های Publish/Subscrib و Event Listener شناخته می شود، شئ ها برای مشاهدۀ یک رخداد که ممکن است توسط یک شئ دیگری بوجود بیاید گماشته می شوند.
- State : یک روش تمیز برای آنکه نوع شئ تا حدی در زمان اجرا تغییر کند.
- Strategy : الگوریتم ها را می توان هنگام پرش انتخاب کرد.
- Template Method : اسکلت برنامۀ درون یک برنامه را توصیف می کند.
- Visitor : یک راه برای جدا سازی یک الگوریتم از یک شئ.
الگو های فرعی :
- Stack (بیرونی کردن پشته) : یک تابع بازگشتی را به یک تابع تکرار شونده تبدیل کنید که از پشته استفاده می کند.
- Hierarchical visitor (بازدید کنندۀ سلسله مراتبی) : راهی برای بازدید از هر اشکال در یک ساختار دادۀ سلسله مراتبی مانند یک درخت فراهم می کند.
- Null Object : طراحی شده است تا به عنوان مقدار پیش فرض یک شئ عمل کند.
- Protocol Stack (قاعدۀ پشته) : ارتباطات توسط چندین لایه مدیریت می شود که یک سلسله مراتب کپسوله سازی را تشکیل می دهند.
- Scheduled-task (وظیفۀ برنامه ریزی شده) : یک کار برنامه ریزی شده است که در یک بازۀ زمانی خاص یا زمانی از ساعت انجام شود (که در محاسبات زنده بکار می رود.)
- Single-serving visitor (بازدید کنندۀ تک خدمت) : پیاده سازی یک بازدید کنندۀ (visitor) مختص را بهینه میکند، نیز یکبار مصرف است و پس از اولین استفاده حذف می شود.
- Specification : منطق تجاری قابل ترکیب به روش Boolean
- Weak reference (مرجع ضعیف) : یک Observer را از یک Observable جدا کنید.
الگوهای Behavioral بیشتر بر جنبه های الگوریتمی چیزها متمرکز هستند. آنها راه دقیق تری برای تعامل و ارتباط اشیاء با یکدیگر فراهم می کنند.
دیزاین پترن Observer
الگوی Observer باید برای هر یک از کسانی که با کتابخانه های برنامه نویسی واکنشی از جمله RxJava، LiveData و kotlin Flow کارکرده باشند آشنا باشد.
اساساً این دیزاین پترن پیوند ارتباطی بین دو شئ را توصیف می کند که یکی از آنها قابل مشاهده(Observable) و دیگری ناظر(Observer) است.
ما یک Observable داریم که چندین رصد کننده آن را رصد می کنند؛ و در دمی که تغییری در آن ایجاد شود رصدکنندگانی که چرخۀ حیات آنها متوقف نشده است متوجۀ آن خواهند شد.
به آن رصدکنندگان Observer می گویند. همچنین در دل همین بحث به زیر بحث هایی از جمله SingleEvents که توقف رصد کردن Observable از سوی Observer به محض مشاهدۀ اولین تغییر در آن بر می خوریم.
این مقاله صرفاً بیان کلیاتی دربارۀ دیزاین پترن ها بود. در سلسله مقالات بعدی در هر یک از مقاله ها یک دیزاین پترن را مورد بحث قرار خواهیم داد.