Design Patterns Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, Copyright © INTEKS LLC,
Design pattern Design pattern is a solution to a problem, which occurs over and over again. Pattern elements: Name – a handle we use to describe a pattern in a word or two Problem – describes when to apply a pattern Solution – describes a set of design elements which solve a problem Consequences – benefits, disadvantages, constraints
Pattern types E. Gamma classification: Creational patterns – abstract the instantiation process and make a system independent on how objects are created Abstract Factory, Factory Method, Singleton Structural patterns – solve objects composition problems Adapter, Bridge, Decorator, Proxy Behavioral patterns - algorithms and the assignment of responsibilities between objects Chain of Responsibility, Command, Iterator, Observer, State, Strategy
Abstract Server Problem: - Button is not reusable in a context not involving a light
Solution Solution: break dependency between Button and Light by inserting an interface
Abstract Server Pattern Benefits: - decouples clients from their servers - can be changed without affecting clients - eliminates DIP violation
Adapter Problem: - Light already exists and can’t inherit from Device - Device might have messages activate/deactivate
Solution - use an adapter to convert one interface to another
Pattern: Adapter Also known as: Wrapper Benefits: - breaks dependency between client and server when server exists - allows different servers to be swapped in and out
Pattern: Adapter A variation, which allows server methods to be redefined
Abstract Client Problem: Server needs to send callback message to client GUI Button is not a reusable class Callback method makes Device unreusable
Solution Server provides interface for client to use
Pattern: Abstract Client Q: What package should contain AbstractClient class ? A: Server’s package
Adapted Client Problem: GUI library components (JButton) do not implement StateListener Solution: use Adapter pattern along with Abstract Client
Singleton Problem: How many database objects do we need in a simple program? Would it be a bad thing is someone mistakenly created more? Solution: prevent programmers from making objects. Make constructors private or protected. make the class responsible for making the one and only object
Singleton Use singleton when: there must be exactly one instance of a class it must be accessible to clients from anywhere inside the program: CompanyDb::Instance()->getEmployee(“Leha”); class CompanyDb { private: static CompanyDb* db; CompanyDb(); ~CompanyDb(); public: static CompanyDb* Instance() { if( 0 == db ) return db = new CompanyDb(); return db; } Employee* getEmployee( const char* name ); };
Monostate Solves the same problem as Singleton All members are static Constructors and destructor are private Class CompanyDb { private: Db db; CompanyDb(); public: static Employee* get Employee( const char* name ); } Db CompanyDb::db = Db( “CompanyName” ); Employee* CompanyDb::getEmployee( const char* name ) { return db.find( “Employee”, name ); } Employee* emp = CompanyDb::getEmployee( “Leha” );
Singleton vs. Monostate Construction: Singleton has lazy construction Don’t pay unless you need it! Monostates are always constructed Singleton can have non-trivial constructors Monostates can’t have non-trivial constructors Destruction: Singleton destruction is not defined Monostate destructon is well-defined
Strategy Problem: - different employees are paid differently - what if we need to add hourly paid manager ? - hierarchy is hard to maintain
Solution PaymentPolicy specifies an algorithm for payment calculation
Strategy Pattern Also known as: Policy Benefits: - different strategies can be swapped in and out - context is closed to changes or additions of strategies
Bridge Problem: - Client code depends on platform - To support a new platform, we need to reproduce all Window’s derivatives
Solution All operations on Window subclasses are implemented in terms of abstract operations from the WindowImp interface Makes Window and its subclasses platform-independent Q: How to make clients independent on WindowImp subclasses? Window drawText() WindowImp drawText() 11 XWindowImp drawText() PMWindowImp drawText() DialogWindowIconWindow Bridge
Bridge Pattern Also known as: Handle/Body Benefits: - Eliminates DIP & OCP violation - Increases maintainability
Proxy Problem: We need to optimize object access in order to make resource allocation operations on demand
Solution Solution: - use a surrogate that will initiate create operation on demand - clients can treat RealImage and ImageProxy as similar objects.
Proxy Pattern Also known as: Surrogate Applicability: - remote proxy - virtual proxy (creation of real object on demand) - protection proxy (for example: ACL support)
Abstract Factory Problem: - creating objects creates a dependency on a concrete type - all other manipulations are done through interface !
Solution Make a class whose responsibility is to make objects Making objects can’t be avoided, but can be contained
Factory Pattern Isolates concrete classes, makes Types family changes easier
Stairway to Heaven Problem: - We wish to make an hierarchy of classes persistent, but we don’t want to depend upon the vendor of our database
Solution Use Adaptor pattern at each level in the hierarchy Requires virtual multiple inheritance Knowledge of persistence Knowledge of business
Visitor What if we need to configure modems differently for different operating systems?
Visitor Problem? ISP violation. Hard to support new OSes.
Solution
Issues Problem? A cycle involving modem implementations. Hard to support new modem types.
New Solution: Acyclic Visitor