-
Notifications
You must be signed in to change notification settings - Fork 26
Home
- Encapsulate what varies.
- Programming to interface not implementation.
- decouple the client code from actual implementation.
- Depenency Inversion Principle: Depend upon abstractions. Do not depend on concrete classes. Our high-level components should not depend on our low-level components; rather than, they should both them depend on abstractions. [p141 HeadFirst] Depend on abstractions, not on concretions.
a class should have only a single responsibility.
“software entities … should be open for extension, but closed for modification”.
“objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program”. See also design by contract.
“many client-specific interfaces are better than one general-purpose interface.”
one should “Depend upon Abstractions. Do not depend upon concretions.” Dependency injection is one method of following this principle.
-
High level modules should not depend upon low-level modules. Both should depend upon abstractions.
-
Abstractions should never depend upon details. Details should depend upon abstractions.
-
Any changes of the low level implementations do not force the high level module to change.
-
in traditional, non-inverted control higher-level components depend on lower-level ones.
-
With inversion of control, the above paradigm is inverted. The high-level components are just abstract classes or interfaces and these are usually (and should be) declared in a package or assembly having no dependency on the code implementing them, and it's the implementation the code that's dependent on higher-level code (because the low-level code must implement a high-level interface or abstract class).
-
What is the meaning of “inversion” in `Dependency Inversion Design Principle
-
DIP reduces coupling between different pieces of code.
-
What is the Dependency Inversion Principle and why is it important?
-
[P141 HeadFirst] راهکارها
-
به هیچ کلاس کانکرتی به طور مستقیم اشاره نکنید. متغیرها نباید به کلاسهای کانکرت اشاره کنند.
-
از کلاسهای کانکرت مشتق نگیرید، به جای آن از اینترفیسها و کلاسهای ابسترکت مشتق بگیرید.
-
متدی را که در کلاس پایه «پیادهسازی» شده است را override نکنید!!
دیاگرامهای کتاب Gang of for بر مبنای OMT هست: Object-modeling technique
#الگوی طراحی Builder
تعریف: الگوی طراحی Builder، روند ساخت یک شیء پیچیده را از نمایش آن جدا میکند به طوری که یک روند ساخت مشترک میتواند برای ساخت انوع نمایشها به کار گرفته شود.
مثال: فرض کنید بخواهیم انواع و اقسام خانهها را طراح کنیم. روند طراحی در تمامی خانهها یکسان است. که به کلاسهای زیر تقسیم میشود:
##Builder
- زیربنای آن را ایجاد میکنیم.
- ساختار و اسکلت آن را ایجاد میکنیم.
- سقف آن را میسازیم.
- فضای داخل خانه را طراحی میکنیم.
بنابراین برای طراحی همهٔ ساختمانها یک رویهٔ یکسان داریم. بنابراین یک کلاس اینترفیس برای تمامی ساختمانها با ۴ رویهٔ مذکور ایجاد میکنیم. که به آن Builder میگوییم.
در این مثال: HouseBuilder
حال به تعداد انواع خانهها، اینترفیس Builder را پیادهسازی میکنم، در این مثال میتوانیم خانهٔ خشتی، خانهٔ گلی، خانهٔ برفی، خانهٔ فلزی، خانهٔ فلزی، خانهٔ چوبی، خانهٔ سیمانی را بسازیم. به هر یک از این کلاسها ConcreateBuilder میگوییم:
- KheshtiBuilder
- GeliBuilder
- BarfiBuilder
- FeleziBuiler
پیمانکار ساختمان، ساختمانها را از طریق اینترفیس House ایجاد میکند. (ورودی: یک نوع خانه از نوع HouseBuilder)
- ساخت زیربنا
- ساخت اسکلت و ساختار ساختمان
- ساخت سقف
- طراحی درون ساختمان
محصول نهایی، حاصل ترکیب تمامی مراحل ساخت یک خانه است.
- خانهٔ گلی
- خانهٔ خشتی
- خانهٔ سیمانی و ...
HouseBuilder builder = new KheshtiBuilder(); Director director = new Director(builder); director.construct();
بیشتر بخوانید:
- Simple Factory (idiom)
- Factory Method Pattern
- Abstract Factory
نکات:
- Factories are used to encapsulate instantiation.
- Factory Method vs. Abstract Factory: An Abstract Factory is used to create a family of related products (Factory Method creates one product).
- Simple Factory returns instances of classes that have the same methods. They may be instances of different derived subclasses, or they may in fact be unrelated classes that just share the same interface. Either way, the methods in these class instances are the same and can be used interchangeably.
- Simple Factory یک الگوی طراحی واقعی نیست. اما به عنوان یک idiom برنامهنویسی بسیار رایج به کار گرفته میشود.
- وصل کردن کد به کلاسهای کانکرت، کد را شکننده و غیرقابل انعطاف میکند.
- جایگزینی اپراتور new با متدهای createConcrete
- میتوانیم از متد استاتیک در این الگو استفاده کنیم.
- استفاده از new باعث ایجاد نمونه از کلاسهای کانکرت میشود.
- استفاده از new یک نوع برنامهنویسی مرتبط با پیادهسازیست تا یک برنامهنویسی مرتبط به اینترفیس. (کد شکننده، خطا پذیر، غیر قابل انعطاف میشود)
- کلاسهای کانکرت معمولاً بیشتر از یک بار یک مکان نمونهبرداری (Instantiate) میشوند.
- بنابراین در صورتی که بخواهیم تغییر بدهیم باید تمامی نمونهبرداریها را در مکانهای مختلف را تغییر دهیم. که این کار طاقتفرسا، سخت و خطاپذیر است.
- Multiple Clinets neeeding same types of object
- Ensure consistent object initialization.
- Depenency
- Loose Couple
- Concrete classes (When you see
new
, thinkconcrete
) - Encapsulating object creation
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
public class SimplePizzaFactory {
// میتوانیم این متود را استاتیک تعریف کنیم تا نیازی به ساخت شیء فکتوری نباشد و بتوانیم مستقیما از کلاس این متود را صدا بزنیم.
public Pizza createPizza(String type) {
Pizza pizza = null;
if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();
} else if (type.equals("clam")) {
pizza = new ClamPizza();
} else if (type.equals("veggie")) {
pizza = new VeggiePizza();
}
return pizza;
}
}
- Simple Factory Pattern Side by Side with Abstract Pattern
- Simple Factory
- ص ۱۱۹ Head First Design Patterns
- The factory method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate.
- Factory Method lets a class deffer instantiation to subclasses.
- Eliminates need to bind creation code to specific subclasses.
- May need to subclass Creator for each ConcreteProduct
- Provides hooks for subclasses.
- Connects parallel class hierarchies.
- در الگوی طراحی Factory Method از Simple Factory استفاده میکنیم.
- در Simple Factory تنها یک کارخانه داریم. اما اگر چند کارخانه داشته باشیم که همگی این کارخانهها محصولات مشابهی تولید کنند مثلاً همگی موبایل تولید میکنند (اما هر کارخانه پیادهسازی خودش را دارد) در چنین حالتی از Factory Method استفاده میکنیم. به این صورت یک رابط برای کارخانهها ایجاد میکنیم و پیادهسازی متود ساخت محصول را به کارخانهها واگذار میکنیم. هر یک از کارخانهها از Simple Factory برای تولید محصولاتش استفاده میکند.
- به روش بالا می گوییم: Allowing the subclasses to decide یا Real-time decision
- برای اینکه پارامترهای Concrete Factory بتوانند
Type-Safe
باشند، میتوانیم ازenum
استفاده کنیم و یا روشهای بهتر. - وقتی که نمونهسازی اشیاء را در یک آبجکت یا متد، کپسوله کنیم، باعث بالا رفتن maintenance میشود و باعث میشود از کدهای اضافی و مجدد خودداری شود.
- Dependency Inversion Principle.
یک واسط برای تمامی موبایلها تعریف میکنیم و ویژگیها و رفتارهای مشترک را ذکر میکنیم.
- نام موبایل
- رنگ
واسط موبایل را برای موبایلهای مختلف پیادهسازی میکنیم.
- Nokia N900
- Nokia N95
- Motorola Atrix
- Motorola A1200
واسط کارخانه createMobile()
هر کدام از کارخانهها باید واسط کارخانه را پیادهسازی کنند.
- NokiaFactory
- MotorolaFactory
- ...
Factory factory = new NokiaFactory()
Car car = factory.createMobile(مشخصات موبایل، نام موبایل، مثل رنگ و ...)
- کلاس SAXParserFactory
- http://javapapers.com/design-patterns/factory-method-pattern/
- http://stackoverflow.com/questions/9963090/factory-pattern-vs-factorymethod-pattern
- http://c2.com/cgi/wiki?FactoryMethodPattern
- اگر
چند نوع محصول
و چند کارخانهٔ مختلف داشته باشیم از Abstract Factory استفاده میکنیم. - The job of an
Abstract Factory
is to define an interface for creatingset of products
.
کارخانهها به سه دسته تقسیم میشوند (نوکیا/سامسونگ/اچتیسی) و محصولات به دو دستهٔ (گوشیهای هوشمند/گوشیهای غیرهوشمند) در این مثال ابتدا یک کلاس انتزاعی از کارخانهها میسازیم که این کلاس دو متد دارد، یکی ساخت گوشی هوشمند آن کارخانه و دیگری ساخت گوشی غیرهوشمند آن کارخانه.
سپس از کلاس انتزاعی کارخانه، سه کلاس نوکیا و سامسونگ و اچتیسی میسازیم که هر کدام از این کارخانهها دو نوع گوشی هوشمند و غیر هوشمند خود را میسازند.
در این مثال، کلاینت ما از نام گوشیها با خبر نیست. مثلاً نمیداند که گوشی هوشمند سامسونگ چیست. کلاینت درخواستش را اعلام میکند. مثلاً میگوید گوشی هوشمند سامسونگ را میخواهم. کلاس کانکرت کارخانهٔ سامسونگ درون کلاس ساخت گوشی هوشمند خود، گالاکسیاس۲ را میسازد.
متن کامل مثال: http://www.codeproject.com/Articles/331304/Understanding-and-Implementing-Abstract-Factory-Pa
- کانستراکتور کلاس را پرایویت میکنیم تا کسی نتواند آن کلاس را خارج از کلاس new کند.
- داخل کلاس یک متود استاتیک تعریف میکنیم و تنها یک نمونه از کلاس تولید میکنیم. اگر قبلاً یک نمونه تولید شده بود، همان نمونهٔ قبلی را برمیگردانیم.
- Singleton in multi-threaded environment
- lazy initialization
- باید این الگو را طوری به کار ببریم که thread safe باشد.
در محیطهای چند نخی، گرفتن و آزاد کردن lock خیلی هزینهبر است و ممکن است تعداد این درخواستها خیلی خیلی زیاد شود. برای کاهش سربار lock میتوان پس از اینکه فلگ را چک کردیم lock کنیم تا سربار کاهش یابد.
- Double-checked locking
- Double-checked locking and the Singleton pattern
- The "Double-Checked Locking is Broken" Declaration
وقتی که ساخت یک شیئ زمانبر و هزینهبر باشد. بهتر است به جای این که برای تعداد زیادی از اشیاء تمام مراحل ساخت شیئ را طی کنیم، یک پروتوتایپ میسازیم سپس از روی آن نمونهبرداری میکنیم و طبق نیازهای خودمان، اشیاء جدید را اصلاح میکنیم. پروتوتایپ: نمونهٔ اولیه، اولین شیای که میسازیم و سپس تمامی اشیاء را از روی این شئ میسازیم.
مثال: ساختن انواع اقسام خانهها خیلی زمانبر است. همهٔ مراحل ساخت این خانهها هم یکسان است. در نتیجه به جای این که هر دفعه که مشتری خانهٔ خاصی (گلی، خشتی، سیمانی و ...) را طلب کرد. از یک نمونهٔ اولیه (پروتوتایپ) که قبلاً ساختهایم یکی فتوکپی میگیریم و سپس متناسب با نیاز مشتری آن را تغییر میدهیم و به مشتری تحویل میدهیم. اینطوری دیگر لازم نیست تمامی مراحل زمانبر ساخت خانه را از اول تکرار کنیم. (DRY)
DRY: Do Not Repeat Yourself
هدف: هر گاه بخواهیم مطمئن شویم که فقط یک نمونه از کلاس میتواند وجود داشته باشد، و دسترسی سراسری به آن داشته باشیم، از این الگو استفاده میکنیم.
- http://stackoverflow.com/questions/86582/singleton-how-should-it-be-used
- http://www.yolinux.com/TUTORIALS/C++Singleton.html
- http://stackoverflow.com/questions/1008019/c-singleton-design-pattern
#الگوی طراحی Adapter هدف: این الگو، اجازه میدهد تا دو اینترفیس ناسازگار با یکدیگر کار کنند.
راههای پیادهسازی:
- چندوراثتی: کلاس Adapter، رو رابط Adaptee و Target را پیادهسازی میکند.
- ترکیب شی (Object Composition)؛ کلاس Adapter، رابط Target را پیادهسازی میکند و درخواستهای Target را برای Adaptee ترجمه میکند.
رابطیست (اینترفیس) که کلاینت از آن استفاده میکند.
شیئایست که با اشیاءای که با Target Interface مطابقت دارند، همکاری میکند.
یک رابط را به رابط دیگر (متناسب با درخواست کلاینت) تبدیل میکند. درخواست کلاینت را میگیرد، و آن را برای Adaptee Interface ترجمه میکند. این کلاس، رابط Target را پیادهسازی میکند
- java.io.InputStreamReader(InputStream)
- java.io.OutputStreamWriter(OutputStream)
- Publishers + Subscribers = Observer Pattern
- Subjects + Observers = Observer Pattern
- Loos coupling
- one-to-many relationship
- minimized interdependency
این الگو زمانی اعمال میشود که Subject-ها و Observer-ها Loose Couple باشند.
- Subject
- Observer
- ConcreteSubject
- ConcreteObserver
انعطافپذیری و تغییر رفتار نمونهها، در زمان اجرا.
##keywords
- wrapper
- aggregation relationship
- Open-Closed Principle (Classes should be open for extension, but closed for modification)
- Component تعریف اینترفیس و تعریف عملیات لازم.
- ConcreteComponent پیادهسازی اینترفیس و عملیات.
- Decorator این کلاس با کامپوننت، رابطهٔ اگریگیشن دارد و داخل خود، یک نمونه از کامپوننت را نگهداری میکند.
- ConcreteDecoratorA
فرض کنید که یک بستنی فروش سه نوع بستنی لیوانی، قیفی و چوبی دارد. این بستنی فروش هنگام فروش هر یک از این بستنیها طبق سلیقهٔ مشتری، بستنی را با عسل، کاکائو، شکلات، بادام و ... تزئین
میکند.
- http://javapapers.com/design-patterns/decorator-pattern/ یک مثال خوب و ساده با جاوا
- java.io.BufferedReader;
- java.io.FileReader;
- java.io.Reader;
MVC بیشتر یک معماری محسوب میشود تا یک الگوی طراحی
در الگوی طراحی استراتژی سعی میکنیم که رفتارهای غیرثابت و متفاوت (استراتژیهای متفاوت)
را از کلاس خارج کنیم و به طور مستقل آنها را کپسوله کنیم. در این صورت هر کلاس، هر کدام از الگوریتمهایی که نیاز داشته باشند را درون خود استفاده میکنند. همچنین این الگو اجازه میدهد تا هر یک از کلاسها هر وقت که بخواهند، استراتژی
خودشان را تغییر دهند.
- Behavioral Pattern
- Strategy at runtime (Change Behavior at Runtime)
- Composition (HAS-A is better than IS-A)
- Strategy lets the algorithm vary independently from clients that use it.
- Strategy at runtime (algorithms can be selected at runtime)
- انتخاب رفتار و
استراتژی
مناسب در runtime - رفتارها و
استراتژیهایی
که طول ساختار وراثتی کلاس تغییر میکند را مشخص کنید و آن رفتارها را از کلاس خارج کنید. و آنها را جداگانه کپسوله کنید. - Separating What changes from what stays the same.
- مزیت
استراتژی
این است که اگر بخواهیم در طول توسعهٔ نرمافزار رفتارها واستراتژیهای
جدیدی تعریف کنیم، نیازی به تغییر کلاسهای اصلی که از این رفتارهای استفاده میکنند نداریم.
- Strategy
- ConcreateStrategy
- Context
![Strategy Pattern](http://yuml.me/diagram/plain;/class/// Non-specific Strategy Class Diagram, [Caller]<>->[<>;Algorithm], [<>;Algorithm]^-.-[ConcreteAlgorithm1], [<>;Algorithm]^-.-[ConcreteAlgorithm2])
Context context = new Context(new ConcreateStrategy1());
context.AlgorithmInterface();
##مثال ۱
فرض کنید که کلاسی داریم به نام Car()
با متودی به نام run()
آنگاه میتوانیم آن را به صورت زیر پیاده کنیم:
Car car = new Car();
car.run();
حالا اگر بخواهیم هنگامی که ماشین روشن است، رفتار ماشین را تغییر دهیم چه کار کنیم؟ مثلاً بخواهیم در نرمافزار بازی دکمهٔ Boost
را شبیهسازی کنیم. چندین روش وجود دارد یکی این که از متغییرهای شرطی و ... استفاده کنیم راه دیگر استفاده از الگوی طراحی استراتژی
هست. مثلاً میتواین حین بازی موتور میاشین را عوض کنیم!! مثال:
Class Car()
{
this.motor = new Motor(this)
// passing "this" is important for the motor so it knows what it is running
method run()
{
this.motor.run()
}
method changeMotor(motor)
{
this.motor=motor
}
}
فرض کنید که یک کارخانهٔ تلفن گوشی همراه داریم. که انواع و اقسام گوشیها را تولید میکند. خب برای پیادهسازی کلاسهای این گوشیها چه کنیم؟
اولی: آیا میتوانیم تمامی رفتارهای مختلف و قابلیتهای گوشیهای مختلف رو در کلاس مادر تعریف کنیم؟
دومی: خیر، چون همهٔ گوشیها همهٔ قابلیتها را پیاده نمیکنند. بعضی از گوشیها دوربین دارند بعضی ندارند. بعضی رادیو دارند بعضی ندارند. بعضی قابلیت اتصال به کامپیوتر دارند و بعضی ندارند.
اولی: خب حالا چه کار کنیم؟
دومی: خب همهٔ قابلیتها را در کلاس مادر تعریف نمیکنیم. سعی میکنیم قابلیتها را در طول ساختار وراثت به سیستم اعمال کنیم.
اولی: اولاً این روش معقولانهای نیست چون برای اضافه کردن هر رفتار و قابلیت جدید باید کلاس و ساختار وراثت را دچار تغییر کنیم. دوم این که باعث ایجاد کدهای تکراری
میشود.
دومی: راهکار چیست؟
اولی: استفاده از الگوی استراتژی
یعنی رفتارهای متغیر را از رفتارهای ثابت جدا کنیم و رفتارهای متغیر را ساختار وراثتی کلاس خارج کنیم. و آنها را کپسوله کنیم.
فرض کنید که قرار است کلاسی بسازیم که آرایهٔ ورودی را مرتب کند. میخواهیم بر اساس نوع دادهها، ترتیب دادهها و پراکندگی دادهها الگوریتم مرتبسازی مناسب را در run-time اعمال کنیم. برای انجام چنین کاری میتوانیم از الگوی استراتژی استفاده کنیم.
- How does the Strategy Pattern work?
- ص ۳۴۹ کتاب Gang of for
- ص ۱۲ کتاب Head First Design Pattern
- Encapsulate a family of algorithms using Strategy Pattern یک مثال خیلی خوب
- یک الگوی طراحی نیست. بلکه
الگوی معماری
است.
![Aggregation vs. Composition](http://yuml.me/diagram/scruffy;/class/[Simcard]<>-->[SmartPhone], [SmartPhone]++-->[Camera])
A Text Editor owns a Buffer (composition). A Text Editor uses a File (aggregation). When the Text Editor is closed, the Buffer is destroyed but the File itself is not destroyed.