Design Patterns Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, 2001-2004 Copyright ©...

Post on 18-Dec-2015

223 views 4 download

transcript

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