آشنایی با مفهوم Design Pattern در جاوا
به عنوان یک برنامه نویس, نیاز است تا با مفهوم Design Pattern آشنا باشیم. با استفاده از این مفهوم, برنامه نویس پروژه ها را در یک ساختار منسجم و مرتب پیاده سازی میکند.
Design Pattern, به روش هایی اطلاق میشود که توسط برنامه نویسان با تجربه در زمینه Object Oriented معرفی شدهاند. هریک از این روش ها برای نیاز ها و پیاده سازی های گوناگونی مصداق دارند. بهتر است برنامه نویسان با Design Pattern ها آشنا باشند تا بتوانند بهترین روش ممکن را برای پیاده سازی پروژه های خود, استفاده کنند.
تاریخچه
در سال ۱۹۹۴, Erich Gamma, Richard Helen, Ralph Johnson و John Vlissides کتابی با عنوان Design Pattern – Elements of Reusable Object Oriented Software را منتشر کردند. آنها در این کتاب, مفهوم Design Pattern را معرفی کردند.
نظریات این مؤلفان بر پایه دو روش است:
- برنامه بر اساس Interface
- استفاده از ترکیب object ها بجای ارث بری
این دو مفهوم ممکن است کمی گنگ باشد. در اینجا این دو مفهوم را بررسی میکنیم.
برنامه بر اساس Interface
همانطور که در ساختار Interface ها مشخص است, تنها قرارداد ها در Interface ها مشخص میشود. به این مفهوم که در Interface ها هیچ پیاده سازی وجود ندارد و تنها ساختار متد ها را در آن ذکر میکنیم. کدنویسی بر اساس Interface به این معناست که همیشه یک Interface وجود داشته باشد که توسط یک سازنده(Factory) پیاده سازی میشود. هر instance که از کلاس Factory برگردانده میشود, باید Interface مدنظر را پیاده سازی کند. با استفاده از این روش, خوانایی پروژه افزایش مییابد و اعمال تغییرات و بروزرسانی پروژه بسیار آسان تر خواهد بود. برای مثال چنین ساختاری را در نظر بگیرید:
public interface Country { String getCapital(); }
سپس یک کلاس factory برای آن ایجاد میکنیم:
public class CountryFactory { public static Country newInstance(Countries countries) { if (countries == Countries.IRAN) { return new Iran(); } else if (countries == Countries.FRANCE) { return new France(); } else if (countries == Countries.GERMANY) { return new Germany(); } else if (countries == Countries.ITALY) { return new Italy(); } else if (countries == Countries.TURKEY) { return new Turkey(); } else { new Throwable("Unknown Country"); return null; } } } enum Countries{ IRAN,TURKEY,FRANCE,ITALY,GERMANY } class Iran implements Country { @Override public String getCapital() { return "Tehran"; } } class Turkey implements Country { @Override public String getCapital() { return "Ankara"; } } class France implements Country{ @Override public String getCapital() { return "Paris"; } } class Italy implements Country{ @Override public String getCapital() { return "Rome"; } } class Germany implements Country{ @Override public String getCapital() { return "Berlin"; } }
اکنون میتوانیم به این صورت از این Interface استفاده کنیم:
Country country = CountryFactory.newInstance(Countries.IRAN); System.out.println(country.getCapital());
همانطور که مشاهده میکنید, در اینجا تمام تمرکز بر روی استفاده از Interafce است. با استفاده از چنین ساختاری میتوان ارتباط با برنامه را بسیار آسان نمود و همچنین خوانایی برنامه افزایش پیدا میکند.
ترکیب object ها بجای ارث بری
ممکن است گاهی در برنامه نویسی و پیاده سازی کد ها, با چالش ارث بری از یک کلاس مواجه شوید. بر این اساس برنامه نویس بر سر دوراهی ارث بری و یا قرار دادن Dependency با استفاده از متد Setter, قرار میگیرد. بنابراین نیاز است تا موارد استفاده از هریک از این روش ها بررسی شود.
مانند تمام ابزار برنامه نویسی, یک trade off برای استفاده از این دو روش وجود دارد. گاهی ممکن است برنامه نویسان بخواهند از خواص یک کلاس استفاده کنند. به این ترتیب بر اساس تعریف ارث بری, باید از این کلاس ارث بری کرده و به متد های آن دسترسی پیدا کنند. اما باید توجه داشت که در اینجا ما تنها از خواص این کلاس استفاده میکنیم. در واقع در اینجا قصد توسعه کلاس را نداریم. واژه reusing در اینجا معنی پیدا میکند. برای استفاده مجدد از یک کلاس نیاز به ارث بری آن نیست و تنها میتوان به عنوان یک Dependency در کلاس مورد استفاده قرار بگیرد. ترکیب object ها برای پیاده سازی ارتباط بین object ها است. استفاده از ترکیب Object باعث میشود تا Dependecy ها از هم متمایز باشند. این مزیت باعث میشود تا محدود سازی Dependency ها به آسانی انجام شود. برای مثال فرض کنید یک کلاس مدل برای یک شهر داریم. این شهر یک سری مختصات جغرافیایی دارد. در ابتدا این تصویر به ذهن میرسد که یک کلاس از نوع مختصات ایجاد کنیم و کلاس شهر از آن ارث بری کند. اما راه حل بهتر این است که یک کلاس به عنوان مختصات ایجاد کنیم و آن را به عنوان یک Dependency به کلاس شهر اضافه کنیم. اکنون مختصات جغرافیایی یکی از خواص کلاس شهر است. همچنین میتوانیم خواصی را به کلاس مختصات اضافه کنیم. ممکن است این خواص در کلاس شهر استفاده نشود. اما در کلاس های دیگر کاربرد داشته باشد.
کاربرد Design Pattern
استفاده از Design pattern, باعث میشود تا یکسری اصطلاحات و واژگان معین برای روش های مشخص, بین برنامه نویسان وجود داشته باشد. برای مثال MVC Pattern یک روش مشخص است که برنامه نویسان میتوانند با استفاده از این Design Pattern, پروژه ها را در قالب مشخصی ایجاد کنند. همچنین روش هایی است که مدت ها در حال استفاده است و چالش های بسیاری را مرتفع کرده است. بنابراین فراگیری این روش ها به برنامه نویسان کمک میکند تا سریع تر و دقیق تر پیشرفت کنند.
انواع Design Pattern
بر اساس آخرین نسخه منتشر شده این کتاب در سال ۲۰۱۶ میلادی, ۲۳ Design Pattern تعریف شده, وجود دارد. با این حال میتوانیم Design Pattern های موجود را به چهار دسته کلی تقسیم بندی کنیم:
- Creational Patterns : روش هایی را برای ایجاد object ها تعریف میکند. در این روش ها منطق ایجاد object مخفی است.
- Behavioral Patterns : روش هایی برای ارتباط میان object ها را تعریف میکند.
- J2EE Patterns : روش هایی را رده Presentation تعریف میکند.
- Structural Patterns : روش هایی برای ترکیب کلاس ها و object ها ارائه میکند. استفاده از ارث بری و یا ترکیب object ها در این نوع Design Pattern تعریف میشود.
در این مقاله سعی بر این شد تا با مفهوم Design Pattern آشنا شویم. با بکارگیری Design Pattern های مناسب میتوانیم خوانایی پروژه را افزایش داده و همچنین بروزرسانی و تغییرات در پروژه را به آسانی اعمال کنیم.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.