Design Patterns Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, 2001-2004 Copyright ©...
-
Upload
anne-armstrong -
Category
Documents
-
view
224 -
download
4
Transcript of Design Patterns Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, 2001-2004 Copyright ©...
Design Patterns
Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, 2001-2004
Copyright © INTEKS LLC, 2003-2004
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
Button
state : bool
push()
Light
turnOn()turnOff()
1
-lamp
1
Solution
Solution: break dependency between Button and Light by inserting an interface
Light
turnOn()turnOff()
Button
state : bool
push()
Device
turnOn()turnOff()
<<Interface>>
1
-device
1
Abstract Server Pattern
Benefits:- decouples clients from their servers- servers can be changed without affecting clients- eliminates DIP violation
Server
ClientAbstractServer<<Interface>>-server
Adapter
Problem:- Light already exists and can’t inherit from Device- Device might have messages activate/deactivate
Button
state : bool
push()
Device
activate()deactivate()
Light
turnOn()turnOff()
Solution
- use an adapter to convert one interface to another
Button
state : bool
push()
Device
activate()deactivate()1
LightAdapter
activate()deactivate()
Light
turnOn()turnOff()1
-device
1
-light
1
Pattern: Adapter
Also known as: WrapperBenefits: - breaks dependency between client and server when server exists - allows different servers to be swapped in and out
ClientAbstractServer<<Interface>>-server
ServerAdapter Server-server
Pattern: Adapter
A variation, which allows server methods to be redefined
ClientAbstractServer<<Interface>>-server
ServerAdapter
Server
Abstract Client
Problem:• Server needs to send callback message to client• GUI Button is not a reusable class• Callback method makes Device unreusable
Device
start()stop()
GUIButton
isOn : bool
setState()
-device
-button
Solution
Server provides interface for client to use
Device
start()stop()
GUIButton
isOn : bool
setState()
-device
StateListener
changeState()
<<Interface>>-button
Pattern: Abstract Client
Q: What package should contain AbstractClient class ? A: Server’s package
Client Server
service()
AbstractClient
callback()
<<Interface>>
Adapted Client
Problem: GUI library components (JButton) do not implement StateListener
Solution: use Adapter pattern along with Abstract Client
GUIButton StateListener
ButtonAdapter Device
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”);
CompanyDb
$ db : Database
Instance()CompanyDb()getEmployee()
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
Director
calcSalary()
Manager
calcSalary()
Employee
calcSalary()
nn
SalariedManager
calcSalary()
HourlyEmployee
calcSalary()
SalariedEmployee
calcSalary()
Solution
PaymentPolicy specifies an algorithm for payment calculation
Director
Manager
Employee
nn
PaymentPolicy
pay()
<<Interface>>
11
-payment
Hourly
pay()
Weekly
pay()
Revenue
pay()
Strategy Pattern
Also known as: PolicyBenefits:- different strategies can be swapped in and out- context is closed to changes or additions of strategies
Context Strategy
algorithm()
<<Interface>>1
Strategy1
algorithm()
Strategy2
algorithm()
Strategy3
algorithm()
1
Bridge
Problem:- Client code depends on platform- To support a new platform, we need to reproduce all Window’s derivatives
Window
XWindow PMWindow
DialogWindowXDialogWindow
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/BodyBenefits: - Eliminates DIP & OCP violation - Increases maintainability
Implementor
operation()
Implementor1
operation()
Implementor2
operation()
Client
Abstraction
operation()11
RefinedAbstration
Proxy
Problem:We need to optimize object access in order to make resource allocation operations on demand
ClientImage
Draw()GetSize()GetPosition()
Solution
Solution: - use a surrogate that will initiate create operation on demand - clients can treat RealImage and ImageProxy as similar objects.
ClientImage
Draw()GetSize()GetPosition()
<<Interface>>
ImageProxyRealImage0..1 0..*0..*0..1
Proxy Pattern
Also known as: SurrogateApplicability: - remote proxy - virtual proxy (creation of real object on demand) - protection proxy (for example: ACL support)
Client Subject
request()
Proxy
request()
RealSubject
request()
Abstract Factory
Problem: - creating objects creates a dependency on a concrete type - all other manipulations are done through interface !
Circle Square
ClientShape
<<Interface>>
<<creates>>
<<creates>>
Solution
Make a class whose responsibility is to make objectsMaking objects can’t be avoided, but can be contained
Circle Square
Shape<<Interface>>
FactoryImp
makeCircle()makeSquare()
Client
ShapeFactory
makeCircle()makeSquare()
<<Interface>>
<<creates>> <<creates>>
Factory Pattern
Isolates concrete classes, makes Types family changes easier
ConcreteFactoryA
createType1()createType2()
ConcreteFactoryB
createType1()createType2()
Type
Type1A Type2A
ClientAbstractFactory
createType1() : TypecreateType2() : Type
Type2A Type2B
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
Type1
Type2
Type3
PersistentObject
load()save()
Solution
Use Adaptor pattern at each level in the hierarchy Requires virtual multiple inheritance
Type1
Type2
Type3
PersistentObject
load()save()
PersistentType1
PersistentType2
PersistentType3
Knowledge of persistence
Knowledgeof business
Visitor
• What if we need to configure modems differently for different operating systems?
ModemDial()Send()Hangup()Recv()
<<Interface>>
SiemensGSMModem ZyxelHwModem WinModem
Visitor
• Problem?• ISP violation. Hard to support new OSes.
ModemDial()Send()Hangup()Recv()ConfigureForWin()ConfigureForLinux()
<<Interface>>
SolutionModem
Dial()Send()Hangup()Recv()accept(ModemVisitor)
<<Interface>>
SiemensGSMModem
ZyxelHwModem WinModem
ModemVisitorvisit(SiemensGSMModem)visit(ZyxelHwModem)visit(WinModem)
WindowsModemConfigurator
public void accept(ModemVisitor v){ v.visit(this)}
Issues
• Problem?• A cycle involving modem implementations. Hard
to support new modem types.
ModemDial()Send()Hangup()Recv()accept(ModemVisitor)
<<Interface>>
ModemVisitorvisit(SiemensGSMModem)visit(ZyxelHwModem)visit(WinModem)
WinModem
New Solution: Acyclic Visitor
Zyxel WinModem
ModemDial()Send()Recv()Hangup()accept(ModemVIsitor)
<<Interface>>
ModemVisitor<<Interface>>
SiemensVisitorvisit(mdm : Siemens)
<<Interface>>
Siemens
ZyxelVisitorvisit(mdm : Zyxel)
<<Interface>>
public void accept( ModemVisitor v) { try { SiemensVisitor sv = (SiemensVisitor) v; sv.visit(this); } catch (ClassCastException e){}}
WinModemVisitorvisit(mdm : WinModem)
<<Interface>>
WindowsModemConfigurator