Title: Design patterns
1Design patterns
- What is a pattern?
- Pattern describes a problem which occurs over and
over again in our environment, and then describes
the core of the solution to that problem, in such
a way that you can use this solution a million
times over , . . . - Christopher Alexander (architecture
theorist)
2Patterns are common
- Design catalogs
- Script writers
- Fashion designers
- Interior designers
- Architects
- Patterns are common tricks used by the profession
- Dont reinventing the wheel
- Simply copy a proven design
3Design Pattern by Gamma et al
- 23 common design patterns divided into 3 groups
- How to create objects (creational patterns)
- How to group them (structural patterns)
- How to use them (behavior patterns)
- Two general approaches in patterns
- Class inheritance
- Object delegation
4- Each pattern has
- Name
- Problem statement
- Solution
- Consequences
- Importance of the name
- To facilitate communication between developers
5Exercises
- Simple quiz
- http//home.earthlink.net/huston2/dp/patterns_qui
z.html - A list of open-end questions
- http//www.industriallogic.com/papers/learning.htm
lQUESTIONS
6Two fundamental principles in OO Programming
- Programming to an Interface, not an
Implementation - so that you can change the implementation easily
in future, the interface is just like a socket - Favour object composition over class inheritance
- To promote more flexible reuse
- Dont overuse inheritance (only for classes that
share the same behavior)
7Example Maze game
- To write a maze adventure game
- The game
- A maze has-a number of rooms
- A room has four sides (North, East, South, West)
- A player enters a side
- If the side is a door, it leads to another room
- If the side is a wall, the player is hurt
- The player wins if a way leaving the maze is found
8The objects
- MazeGame, Maze, Room, Door, Side
- Polymorphism
- Group Room, Door and Side under the abstract base
class MapSite - Base class virtual function
- Enter()
- How to build the maze using OO concepts?
9Is-a relation
- A Room is-a kind of MapSite
- A Door is-a kind of MapSite
- A Wall is-a kind of MapSite
- Is-a suggests class inheritance
MapSite
Is-a
Room
Door
Wall
10Is-a relation
- Skeleton code
- class MapSite //ABSTRACT class
- public virtual void Enter()
-
- class Room MapSite //CONCRETE class
- public override void Enter()
//implementation -
- Room.Enter() - enter a room
- Door.Enter() - enter the room beyond the door
- Wall.Enter() - get hurt, stay at the same room
11Has-a relation
- A maze has-a number of rooms
- A room has four sides
- A room may have several smaller rooms
- Has-a suggests object composition
12A UML diagram describing the maze structure
Recursion. Known as Composite pattern
MapSite Enter()
Has-a
Room Enter() SetSide() GetSide() RoomNo
Wall Enter()
Door Enter()
rooms
Maze AddRoom() RoomNo() ArrayList _rooms
Has-a
13Object composition
- Maze is composed of (has-a) Rooms
- Room is composed of Doors, Walls and Rooms.
- class Maze
- private ArrayList _roomsnew ArrayList()
- //a typeless container that holds the rooms
-
- class Room MapSite
- public override void Enter() //. . .
- private MapSite _sides new MapSite4
-
14Wall, Door
- class Wall MapSite
- public override void Enter() . . .
-
- class Door MapSite
- private Room _room1
- private Room _room2
- public Door(Room r1, Room r2) . . .
- public override void Enter() . . .
-
- static void Main()
- . . .
- MazeGame game new MazeGame()
- _aMaze game.CreateMaze() //create the
maze - . . .
-
15MazeGame.CreateMaze() creates a simple maze
N
Room 2
Room 1
aWall
Objects structure
aDoor(r1,r2)
_aMaze _rooms
aWall
r2 . . .
aWall
16- Maze MazeGame.CreateMaze()
- Maze aMaze new Maze() //create a maze
object -
- Room r1 new Room(1) //create rooms
- Room r2 new Room(2)
- Door theDoor new Door(r1, r2) //create door
- r1.SetSide(North, new Wall()) //add wall to
room - r1.SetSide(East, theDoor()) //add door to
room - r1.SetSide(South, new Wall())
- r1.SetSide(West, new Wall())
- // . . . init r2 like r1
- aMaze.AddRoom(r1) //add to container
- aMaze.AddRoom(r2)
- return aMaze
17What is wrong with CreateMaze()?
MazeGame Maze MazeGame.CreateMaze() Maze
aMaze new Maze() Room r1 new
Room(1) Room r2 new Room(2) Door theDoor
new Door(r1, r2) . . . return aMaze
18What if . . .
- in future, we would like
- to CREATE a different kind of room?
- to CREATE a different kind of door?
- to CREATE a different kind of wall?
- We need to change the code in CreateMaze()
19This is what we have to do break the old code !
MazeGame Maze MazeGame.CreateMaze() Maze
aMaze new Maze() Room r1 new
EnchantedRoom(1) Room r2 new
EnchantedRoom(2) Door theDoor new
DoorNeedSpell(r1, r2) return aMaze
20Solutions?
- Class inheritance
- Factory method
- Object delegation
- Abstract factory
- Builder
- Prototype
21Factory method
- Replace new by virtual function
- Virtual function can be overrided by the
subclass, so that different objects can be created
MazeGame Maze MazeGame.CreateMaze() Room
r1 MakeRoom(1) //. . . //base class
default MakeRoom() Room MazeGame.MakeRoom(int n)
return new Room(n)
22Let subclass to override the factory method
MazeGame Maze MazeGame.CreateMaze() Room
r1 MakeRoom(1)
EnchantedMazeGame //override base class
MakeRoom() Room EnchantedMazeGame.MakeRoom(int
n) return new EnchantedRoom(n, SpellDoor())
23Change one line and have a different MazeGame
- public class Form1 Form
- Maze _aMaze
- static void Main()
- using (Form1 form new Form1())
- form.InitializeGame()
- Application.Run(form)
-
-
- private void InitializeGame()
- //MazeGame game new MazeGame()
- MazeGame game new EnchantedMazeGame()
- _aMaze game.CreateMaze() //create the
maze -
- //. . . code for the event handlers
24Factory Method
- Define an interface (the virtual functions) for
creating an object, but let subclasses decide
which class to instantiate. - Factory Method lets a class defer instantiation
to subclasses. - Also known as virtual constructor
25Framework, toolkit and application
- What is the difference between framework, toolkit
and application? - Framework has the highest degree of reuse, and is
the most flexible - Application is the least flexible
26What is a framework?
- A framework is an abstract type of software that
captures the design decisions that are common to
its application domains - e.g. what is the similarity between a circuit
design editor, and musical score editor? - Both manipulate graphical objects
- An abstract software (framework) that can support
both applications?
27A general framework for graphical processing
Framework
AbstractFramework NewDoc() AbstractGraphic g g
CreateGraphic()
AbstractGraphic Move() Scale()
MyGraphic
MyGraphicApplication CreateGraphic() //factory
method return new MyGraphic()
28A framework for graphical processing
- The concrete MyGraphic object can be any graphic
symbols, e.g. musical notes, circuit symbols - These objects can be manipulated by a uniform set
of operations (e.g. Move(), Scale(), etc) - Code in framework knows how to manipulate the
abstract base class AbstractGraphic object - The concrete subclass object (MyGraphic ) is
created differently for different application
29A musical score editor
Framework
AbstractFramework NewDoc() AbstractGraphic g g
CreateGraphic()
AbstractGraphic Move() Scale()
MyMusicScore
MyMusicScoreApplication CreateGraphic() //factory
method return new MyMusicScore()
30A electronic circuit editor
Framework
AbstractFramework NewDoc() AbstractGraphic g g
CreateGraphic()
AbstractGraphic Move() Scale()
MyCircuit
MyCircuitApplication CreateGraphic() //factory
method return new MyCircuit()
31- Thinking in two levels
- Abstract level (framework level)
- I (framework) dont care what the symbols
(objects) are about ! - My job is just to move, to scale, to draw, and to
print the symbols - How to draw/print the symbols? That is the job of
the symbols themselves (think like a boss!) - Concrete level
- All the (dirty) real work is done by me (concrete
objects)
32What is a framework?
- Framework emphasizes design reuse rather than
code reuse - Framework contains the main program, users
customize the framework by providing the concrete
subclasses - Modern systems have layers of frameworks that
cooperate with each other
33Toolkit
- Toolkit is just a set of reusable classes,
providing the functionality - Emphasize code reuse
- Users write the main program, toolkit provides
reusable code - Framework is harder to code than toolkit
- Toolkit is harder to code than application
34Pros and cons of class inheritance
- Pros
- Simpler than object delegation, codes are easier
to follow - Cons
- Static binding, fixed at compilation time, cannot
be changed at run-time - Need to create new subclass
- Ways to reduce the number of subclasses?
35Parameterized factory methods
- The method takes a parameter that identifies the
kind of product - Parameterized factory methods reduce the number
of subclasses that are needed - Use
- In document applications, different document type
has different file extent (.doc, .xml, .txt, . .
.)
36Parameterized factory methods
- class Creator
- public virtual Product Create(int id)
-
- class ConcreteCreator Creator
- public override Product Create(int id)
- if (idA) return new ProductA
- if . . .
- return base.Creator(id)
-
-
37Use Generic to avoid subclassing
- Problem with factory methods
- For every new product, you need to subclassing
the Creator for creating the product - Use Generics to void subclassing
- The code for the subclass is automatically
generated by the compiler - In the following example, GenericCreatorltTgt is
just a template, compiler uses it to generate the
code
38Use Generic to avoid subclassing
- class Creator
- public virtual Product Create()
-
- class GenericCreatorltTgt Creator
- public override Product Create()
- return new T()
-
-
- Main()
- Creator myCreator new GenericCreatorltProductAgt
() - Product p myCreator.Create() //factory
method -
39The code generated
- class GenericCreator Creator
- public override Product Create()
- return new ProductA()
-
-
40Create objects by Object Delegation
MazeGame CreateMaze(f) //f is a factory
object Maze aMaze new Maze() Room r1
f.MakeRoom(1) Room r2 f.MakeRoom(2) //. .
. return aMaze
AbstractFactory MakeRoom(int n)
delegate
ConcreteFactory MakeRoom(int n) return new
Room(n)
MakeRoom is a factory method
41Abstract Factory
- In many applications, we dont change just one
type of object, but, rather, a family of objects - This can be done by using a factory object
- To select a different game at run-time
- Just change the (concrete) factory object f
- Abstract Factory provides an interface for
creating families of related or dependent objects
without specifying their concrete classes
42Example - the Look-and-Feel Problem
- How to change the look and feel of the desktop at
run-time? - e.g. change to MotifWindow, MSWindow,
AppleWindow - Solution
- Choose a concrete factory object
- MotifFactory, MSFactory, or AppleFactory
- The factory object creates the concrete products
- MSWindow, MSScrollBar, . . .)
- but returns them as abstract products
- Window, ScrollBar
43Abstract Factory client uses an abstract
factory GUIFactory to produce abstract products
delegate
GUIFactory CreateScrollBar() CreateWindow()
client
Window
Is-a
Is-a
MSWindow
MotifWindow
MotifFactory CreateScrollBar() CreateWindow()
ScrollBar
MSFactory CreateScrollBar() CreateWindow()
MSScrollBar
MotifScrollBar
44Abstract Factory
- GUIFactory guifactory
- //choose a concrete factory object
- if (strcmp( inputName, Motif) 0 )
- guifactory new MotifFactory()
- else
- guifactory new MSFactory()
-
- //factory returns abstract product
- Window w guifactory.CreateWindow()
- w.Draw()
Different factory creates different concrete
product
Return the abstract product, upcasting,
polymorphism
45Builder
- Problem
- To build a complex object, e.g. a building, an
aircraft - The complex object has different representations
- i.e. we can look at the object at different ways
- e.g. different representations of an aircraft
- Its look
- Its total weight
- Its total cost
46Builder
- What to reuse?
- The construction of the object is complex
- Want to reuse the construction process so as to
create different representations - Solution?
- Separate the construction of a complex object
from its representation so that the same
construction process can create different
representations
47Builder
Construction
MazeGame CreateMaze(builder)
builder.BuildMaze() builder.BuildRoom(1)
builder.BuildRoom(2) //. . . return
builder.GetMaze()
AbstractBuilder buildRoom(int n)
delegate
ConcreteBuilder buildRoom(int n) return new
Room(n)
Representation
48Builder
- Change the concrete Builder, get a different
product - Example
- CountBuilder
- To count the number of parts (rooms, doors) used
in the maze - SimpleBuilder
- Return a simplified graphical maze object that is
good for low-end mobile phone
49Intent and its importance
- Abstract Factory and Builder are different
patterns for solving different problems - But they have the same code structure !!
- They have the same UML diagrams
- Code is not everything
- Should also know the intent of the code
50Difference between Abstract Factory and Builder
- Their intent are different
- Abstract Factory
- Provide an interface for creating families of
related or dependent objects without specifying
their concrete classes - Builder
- Separate the construction of a complex object
from its representation so that the same
construction process can create different
representations
51Abstract Factory and Builder
- Abstract Factory focuses on building a families
of parts (either simple or complex), and returns
the part immediately - Client assembles the parts into complex object
- Builder returns the product as a final step
- The concrete parts in the complex object is
encapsulated inside the Builder - Parts have different representations that are
hidden from the client - Appearance, weight, cost, . . .
- Change Builder, change representation
52Problem
- To build a maze that allows player to choose the
composition of the maze at run-time - e.g. the maze can be made up of EnchantedRoom,
DoorWithSpell and BombedWall - The problem is like creating an ice cream object
with different combination of favours - Use a factory to build these parts so that player
can choose the composition dynamically
53Problem with subclassing
AbstractFactory
Factory1 Door Wall Room
Factory2 DoorWithSpell Wall Room
Factory3 Door BombedWall Room
Factory4 Door Wall EnchantedRoom
Factory5 DoorWithSpell BombedWall Room
Factory8 DoorWithSpell BombedWall EnchantedRoom
. . .
54Combinatorial problem
- If we have 5 different types of rooms, doors and
walls, we have 555 different combinations - Need to create 125 subclasses !
- Class explosion, a common problem with
subclassing - A better approach - composition
- Construct a prototype object at run-time
- The prototype is composed of
- EnchantedRoom, DoorWithSpell and BombedWall
- Prototype is a factory object that manufactures
the parts by cloning
55The Prototype MazePrototypeFactory factory
- class MazePrototypeFactory MazeFactory
- public MazePrototypeFactory(Maze m, Wall w,
- Room r, Door d)
- public virtual Maze MakeMaze()
- public virtual Room MakeRoom(int i)
- public virtual Wall MakeWall()
- public virtual Door MakeDoor(Room r1, Room r2)
- private Maze _prototypeMaze
- private Room _prototypeRoom
- private Wall _prototypeWall
- private Door _prototypeDoor
56To create the prototype object
- int Main()
- MazeGame game
- MazePrototypeFactory factory(new Maze(), new
BombedWall(), new EnchantedRoom(), new
DoorWithSpell()) - Maze maze game.CreateMaze(factory)
- . . .
-
Construct a Prototype factory object
factory Maze _maze new Maze() Wall _wall new
BombedWall() Room _room new EnchantedRoom() Door
_door new DoorWithSpell()
57The prototype constructor
- Create the prototype object by composition
- MazePrototypeFactory(Maze m, Wall w, Room r, Door
d) -
- _maze m //point to an concrete object
- _wall w
- _room r
- _door d
Has-a relation (a prototype has-a maze, wall,
room and door) Also known as composition
58How to use it?
- We use the prototype factory object like an
Abstract Factory object - Maze MazeGame.CreateMaze(MazeFactory factory)
-
- Maze aMaze factory.MakeMaze()
-
- Room r1 factory.MakeRoom(1)
- . . .
-
- So what is inside factory.MakeRoom()?
59How to use it?
- factory.MakeRoom() uses the existing Room object
to clone a new EnchantedRoom
Room Room Clone()
createMaze(factory) r1factory.MakeRoom(1)
MazeFactory
MazePrototypeFactory private Room _room Room
MakeRoom(int i) r_room.Clone() r.Number
i return r
EnchantedRoom Room Clone() Room rnew
EnchantedRoom() //copy attributes from this
return r
A clone of EnchantedRoom
60Summary Creational Patterns
- Factory Method Define an interface for creating
an object, but let subclasses decide which class
to instantiate. Factory Method lets a class defer
instantiation to subclasses - Abstract Factory Provide an interface for
creating families of related or dependent objects
without specifying their concrete classes - Builder Separate the construction of a complex
object from its representation so that the same
construction process can create different
representations - Prototype Specify the kinds of objects to create
using a prototypical instance, and create new
objects by copying this prototype
61Singleton
- How to create one and only one instance of a
class, - e.g. a single print queue shared by many printer
- a single window server for the user interface
- The single object must be easily accessible
- Intent
- Ensure a class only has one instance, and provide
a global point of access to it
62The consideration
- To make the object easily accessible
- Use a global/static object
- Drawback
- No guarantee that there is only one instance of
the class, e.g. - static Singleton object_1 new Singleton()
- static Singleton object _2 new Singleton()
- Problem - two objects of the same class
- Solution - use a private constructor !
63Use private constructor and public method
- sealed class Singleton
- protected Singleton()
- private static Singleton _instancenull
- public static Singleton Instance()
- if (_instancenull)
- _instance new Singleton()
-
- return _instance
-
-
- Main() //to use a Singleton
- Singleton server1 Singleton.Instance()
-
- Singleton server3 new Singleton()
- //wont compile, constructor is protected
64- Singleton() is private object can only be
created via the function Instance() - Instance()controls the number of objects created
- But Instance()is an object level method
- With a private constructor, we have a problem in
creating the first object - Without an object, we cannot invoke Instance()
- Instance() must therefore be a class level
(static) method
65- Creational patterns
- Create objects flexibly
- Structural patterns
- Group objects together to form more complex
structure
66Adapter
- Problem
- A bank is developing a new system with a new
interface, how to reuse the old (legacy) system ?
client
INewSystem NewRequest()
OldSystem OldRequest()
67Class Adapter
Object Adapter
Old
New
New
Old
ClassAdapter
ObjectAdapter
68Class Adapter - by class inheritance
client
INewSystem NewRequest()
OldSystem OldRequest()
69Class Adapter
- public class ClassAdapter OldSystem, INewSystem
- public void INewSystem.Request()
- base.OldRequest() //base refers to OldSystem
-
-
- Main()
- INewSystem sys new ClassAdapter()
70Problems
- Modern OO languages (C, Java) only support
single implementation inheritance - Cannot hide the old implementation
- Interface in OldSystem can be exposed by casting
- class ClassAdapter private OldSystem,
INewSystem - Object Adapter does not have these problems
Ideal, but not supported in C
71Object Adapter
client
NewSystem NewRequest()
OldSystem OldRequest()
adaptee
Object Adapter NewRequest()
adaptee-gtOldRequest()
72Object Adapter
- public class ObjectAdapter NewSystem
- private OldSystem _oldSys new OldSystem()
- public void NewRequest()
- _oldSys.OldRequest() //delegation
-
-
- Single implementation inheritance
- Interface of the old system is hidden from client
73Adapter
- Also Known as
- Wrapper
- Intent
- Convert the interface of a class into another
interface clients expect. - Adapter lets classes work together that couldnt
otherwise because of incompatible interfaces
74 Problem
- To support a computer game for two different
hardware platforms - Solution by subclassing
Game
abstraction
implementations
XBoxGame
PSGame
75Bridge
- Problem with extending the abstraction
- To add a platform (Nokia phone), need to port the
implementation of the game to the new platform - A better solution
- Separate the platform-specific code from the
abstraction (of the game)
76Bridge
- Decouple (separate) an abstraction from its
implementation so that the two can vary
independently
imp
Implementor Operation()
Abstraction
imp.Operation()
Imp_1
Abstract_2
Abstract_1
Imp_2
Imp_3
77Abstraction Implementation
GameImp DevDrawText() DevDrawLine()
Game DrawText() DrawRect() GameImp imp
imp
imp.DevDrawLine()
ConcreteGame1 DrawBorder()
PSImp
XBoxImp
DrawRect() DrawText()
78Bridge
- IntentDecouple an abstraction from its
implementation so that the two can vary
independently - The Graphics object in GDI is an example of
Bridge pattern - GDI, platform specific code is separated and
encapsulated in a Graphics object - Different Graphics object can be used to
represent different graphic card
79Composite
- A graphics application has primitives (line,
circle), which can be grouped to form a larger
component - Component is just a container
- Components can be grouped to form an even larger
components - Problem
- How to treat primitives and components uniformly
- e.g. if g is a line, g.Draw() will draw a line
- if g is a component, g.Draw() will draw all the
composition recursively
80Composite
- Uniform interface - suggest the use of a base
class
Graphic Draw()
Picture Draw()
Circle Draw()
Line Draw()
81Composite
- A Picture is a Composite (has-a
pictures/primitives) - Recursion
Graphic Draw()
Picture Draw()
Circle Draw()
Line Draw()
82- Recursive object structure
aPicture
aLine
aCircle
aPicture
aLine
aCircle
aPicture
83Composite code example
- class Graphic
- public virtual void Draw()
- //. . .
-
- class Picture Graphic
- private ArrayList graphics //container
- public void Draw()
- foreach (object o in ArrayList)
- Graphic g (Graphic) o
- g.Draw() //if g is-a line, draw line
- //if g is-a picture, recursion
84Composite
- Intent
- Compose objects into tree structures to represent
part-whole hierarchies. Composite let clients
treat individual objects and compositions of
objects uniformly - Note
- Part-whole hierarchies are extremely common,
making Composite one of the most useful pattern
85Decorator
- Problem
- How to create a reader object that can
- Read a stream from the file
- Decrypt the stream
- Perform a formatted read (read an integer,
double, etc, from byte stream) - How to build this reader object flexibly?
86Class inheritance approach
- Create more specialized objects by subclassing
- The concrete BinaryRead object
- use FileStream code to read the file
- use CryptoStream code to decrypt the file
- use its own code to do formatted read
FileStream
CryptoStream
BinaryReader
87Class inheritance approach
- Combinatorial problem, need many subclasses
- Static binding cant change at run-time
- Object delegation
- More flexible than by subclassing
- Concept is similar to piping in Unix, a complex
object is formed by joining several objects
together
Structure of a decorator
88Decorator
- To create new object by composition and perform a
chain of actions - FileStream.Read() then CryptoStream.Read()
then BinaryReader.ReadXxx()
A decorator object
CryptoStream Read() Stream _next
FileStream Read() Stream _next
BinaryReader ReadXxx() Stream _next
89Decorator object diagram
Has-a relationship Software piping by delegation
BinaryReader Stream _next ReadXxx() if
(!_next) _next.Read() //format data
CryptoStream Stream _next Read() if (!_next)
_next.Read() //decrypt data
FileStream Read() //read data
90Decorator class diagram
- To support composition of indefinite number of
objects
Stream Read(byte buffer, int offset, int count)
1
ConcreteStream Read(. . .) Stream _next
Has-a
91Class diagram of System.IO in C
Reader has the same class diagram as Writer
TextWriter
BinaryWriter
Stream
StreamWriter
StringWriter
CryptoStream
FileStream
BufferStream
NetworkStream
Note the decorator pattern
92The structure of the IO design
- TextWriter class
- For writing characters
- StreamWriter for writing a indefinite sequence
of characters - BinaryWriter class
- Class for writing a binary stream
- Stream class
- For adding different features flexibly using the
decorator pattern
93Example
- An object that formats, encrypts, and writes to
file - using System
- using System.IO
- using System.Security.Cryptography
- static void Main(string args)
- //initialization code skipped
- FileStream fout new FileStream(. . .)
- CryptoStream cs new CryptoStream(fout, . . . )
- BinaryWriter bw new BinaryWriter(cs)
- bw.Write("hello world")//format, encrypted,
write to file - bw.Close()
- cs.Close()
- fout.Close()
94Decorator
- Also known as
- Wrapper
- Intent
- Attach additional responsibilities to an object
dynamically. - Decorators provide a flexible alternative to
subclassing for extending functionality - Known Uses
- I/O objects in C, Java
- graphical user interface (see text)
95Façade
- Problem
- Objects have too many dependency, how to reduce
the dependency?
Subsystem
96Façade
- Solution
- Create Subsystem with a single and unified
interface
Facade
Subsystem
97Façade
- Intent
- Provide a unified interface to a set of
interfaces in a subsystem. Façade defines a
higher-level interface that makes the subsystem
easier to use - Façade objects are often Singletons
- C internal keyword
- A subsystem has public classes and encapsulated
private classes - Use internal keyword for encapsulating classes
within an assembly, and public keyword for the
Façade public class
98Proxy
- Problem
- Some objects are expensive to create
- e.g. a large document with many objects (text,
images) - Create all the objects at once takes too long
- Solution
- Create a proxy object quickly
- Only create the objects when they are needed
(visible in the document)
Proxy
99Proxy
- ImageProxy is an object that can be created very
cheaply, it maintains a reference to the image on
disk
aTextDocument image
anImageProxy fileName
anImage data
in memory
on disk
100Image Proxy
Graphic Draw()
client
realSubject
ImageProxy Draw() Image image
Image Draw()
(has-a)
//draw only on-demand if(image 0)
imageLoadImage(fileName) image.Draw()
101Proxy server example
WebServer Get(url) . . .
client
WebProxy Get(url) . . .
OriginServer Get(url) . . .
//get over the net only on-demand if(
url_not_in_cache ) urlserver.Get(url) retu
rn url
102Proxy application
- virtual proxy (as in our example)
- creates expensive objects on demand
- e.g. virtual memory in an OO Unix
- remote proxy
- provides a local representative for an object in
a different address space (e.g CORBA, RMI, .NET) - protection proxy
- control access to the original object
(authentication) - smart reference
- replacement of a bare pointer that performs
additional actions, e.g. web page filtering
103Flyweight
- A pattern for system that has a large number of
tiny objects - Scenario
- In a word processing application, we have
- row objects
- column objects
- character objects
- A column may have several rows, and each row may
have many character objects - Use Composite Pattern to model this structure
104Flyweight
- Composite Pattern
- All objects are treated uniformly by the
functions provided in base class Glyph - Captures the tree-structure of the document
Glyph
Glyph
Row
column
105Flyweight
- Problem
- Large number of small objects !
- One page 500 words 2500 characters (objects)
106Flyweight
- Solution
- Each character object is a singleton shared in a
pool
107An object has
- Sharable attributes
- e.g. the character code
- Non-sharable attributes
- e.g. font type and font size
- Sharable attributes are stored in Singleton
objects, located in a sharable flyweight pool - The non-sharable attributes are stored in a
context object (GlyphContext) - Example of non-sharable context
- font size, font type
108Represent the context by a table
- The table can be implemented using Dictionary
that supports the IDictionary interface - Dictionary has a collection of key/value pairs
- Key position, stringcontext
- int(key) string(value)
- Times 24 //1 char
- Times 12 //next 100 char
- Times-Italic 12 //next 6 char
- Times 12 //next 194 char
- . . .
109Flyweight
- To draw a Character object
- Glyph.Draw() is not enough
- Character contains only the sharable attributes,
need the GlyphContext object to get the context - Glyph.Draw(GlyphContext)
- complete information Glyph GlyphContext
110- Creational patterns
- How to create objects flexibly
- Structural patterns
- How to group objects together
- Behavioral patterns
- How to use objects in a collaborative way
- The key - identify the responsibilities of the
objects
111Course Registration System
- Design a course registration system to support
- Course browsing
- Course registration
- Constraint checking (e.g. pre-requisite)
- Course functions (e.g. print course list)
- Problem
- What is the object structure that we should use?
112- Arrange the courses by a tree structure
university
Science
Engineering
Law
IE
composite
CSE
leaf
IEG3080
113Composite pattern
Node string _name
NodeList //nameErg,Sci,...
Course //nameIEG3080 ...
114Problem - GUI framework to support course
browsing?
Menu bar
Course Info
Registration
ALL ART MED SCI
Menu
ACE CE CS EE SEEM
ERG
Menu item
IE
IEG1110 IEG2220 . . .
IEG3080
115Browsing
ALL ART ERG MED SCI
- The menu
- Menu item
- ALL, ART, ERG, . . ., IE, . . ., IEG3080
- Each item has a different Action
- ALL will list all courses provided
- ART will list all courses in ART faculty
- IEG3080 will list course info in IEG3080
116- A GUI framework can only provide the following
abstract widgets - Menu
- MenuItem
- A Menu has-a number of MenuItems
- Select a MenuItem, an action will be executed
- How to associate the MenuItem with your action?
Your action
MenuItem
GUI framework
117By class inheritance
- MenuItem is an abstract base class that has an
Execute() - Subclass implements Execute()
- Simple, static binding
Abstract framework
MenuItem Execute()
Menu
MyMenuItem Execute()
Action()
118By object delegation
Abstract framework
lthas-agt
Command
MenuItem Command c Clicked()
Menu
c-gtExecute()
CommandA Execute()
CommandB Execute()
Action1()
Action2()
119Command object
- Put a Command object inside a MenuItem object
- aMenuItem.StoreCommand(Command c)
- If MenuItem is clicked, c.Execute()is called
- A difference between inheritance and delegation
- Inheritance binded MenuItem with the action
- Delegation decouples the two
- The decoupling leads to a better reuse of the
Command object (it can be used by more than one
MenuItem )
120How to support Undo /Redo ?
- Each command object supports Execute() and
UnExecute() - Clone a command object
- Put the cloned object in a command history list
- Redo gt clonedObject.UnExecute()
past commands
present
121Command
- Intent
- Encapsulate a request as an object
- Applications
- Each MenuItem has a command object
- e.g. new MenuItem(new IEG3080())
- The .NETs delegate is an example of command
122Problem
- To check whether a student can register to a
course - need to check the course, department, faculty,
and university constraints - Example of constraints
- credit exceeded, pre-requisites not met
- Problem
- Which object is responsible in doing the checking?
123Chain of Responsibility
- A simple solution
- Pass the request along a chain of responsibility
- Each object on the chain shares a common
interface - It is like getting a form signed but you dont
know who should sign it - So pass the form around until someone could
handle it
124Chain of Responsibility
- Often applied in conjunction with Composite (i.e.
tree structure)
client aHandler
IEHandler successor
ErgHandler successor
UniHandler successor
CSHandler successor
SciHandler successor
125Chain of Responsibility
Handler Request()
client
successor
ConcreteHanlder1 Request()
ConcreteHanlder1 Request()
126Chain of Responsibility
- Intent
- More than one object may handle a request, and
the handler is not known - You want to issue a request to one of several
objects without specifying the receiver
explicitly - The structure is similar to a composite pattern
- But composite pattern is focused on the structure
of the objects - Chain of Responsibility is focused on the
behavior of the objects
127Problem multicast relationship
- How to define a one-to-many dependency between
objects so that when one object changes state,
all its dependents are notified and updated
automatically - e.g.
Central timer
Central Timer changes state Notify all other
clocks
1000am
200am
1000pm
HK time
London time
New York time
128Observer Pattern
- Key abstraction
- Subject (e.g. central timer)
- Observers (e.g. different clock)
- Whenever the Subject changes its state, it
notifies (Update()) all the Observers - Each Observer responds by getting the up-to-date
information (GetState()) from the Subject - A new Observer can attach itself to the container
of the Subject
129Observer Pattern
1
Observer Update(subject)
Subject Attach(Observer) Detach(Observer) Notify()
observers
Foreach o in observers o.Update(this)
ConcreteObserver Update(subject)
ConcreteSubject GetState() . . .
observerState subject.GetState()
130The multicast protocol
- Subject has a list of Observers
- An Observer uses Attach() and Detach() to add
itself to Subjects list - Subject uses Update() to send notification to
Observers - Pass itself to Observers as parameters
- Observers use the passed Subject to get the new
state information
131GUI problem
- User uses a mouse to click a button on the screen
- Window manage detects the mouse click event
- But how could the manager notify the button
handler?
Window manager
?
MyButtonHandler Update()
Mouse click
Button
132Class inheritance
- Used by early version of MFC and Java (ver 1.0)
Window manager
Mouse click
Button Update()
MyButtonHandler Update()
133Class inheritance
- User clicks Button , the manager uses the current
mouse position to locate Button - Manager calls Button.Update()
- MyButtonHandler inherits the Button interface,
MyButtonHandler.Update() is called - Limitation
- Do not support multicast
- Static binding, relationship is fixed at compile
time, cannot attach or detach at run time
134Object delegation
- Used by current version of Java (the name
Listener is used instead of Observer) - Advantages
- Support multicast and dynamic binding (so that
user can attach and detach observer at run time)
Window manager
Mouse click
Button Update() Listener list
Observer Update()
MyButtonHanlder Update()
135Further improvement on the Observer pattern
- Problem with Observer
- Every event handler must inherit the Observer
base class (which provides the Update()
interface) - The Subject passes itself as argument to the
Observer - How to specify the type of the Subject flexibly?
- Delegate
- An improved version of Observer
- Use a Command object to encapsulate a pointer to
the handler, eliminate Update() and the base
class Observer
136Callback by delegation (in L3 notes)
- class MyWindow Form
- static void Main()
- Application.Run(new MyWindow())
-
- public MyWindow()
- this.MouseUp new EventHandler(this.Handler())
- //MouseUp is a container
- private void Handler(object sender,System.EventAr
gs e) - Console.WriteLine(call from 0,sender.ToStrin
g()) -
Command object
function pointer
Handler function
137C delegate
- User can also define a delegate with signature
- More flexible, can pass type-safe information
- public delegate void MyHandler(Student s)
- Delegate Command Observer pattern
Window manager
C delegate object
Button Update() Listener list
Command
MyHandler Handler()
Command has a pointer to Handler()
138Mediator
- Problem
- OO encourages distribution of responsibility, but
this frequently leads to many connections between
objects - The system is difficult to change because each
object depends on many other objects
139Mediator
- Solution
- Promotes loose coupling between objects via a
central mediator
mediator
140Mediator
- Intent
- Define an object that encapsulates how a set of
objects interact - Mediator promotes loose coupling by keeping
objects from referring to each other explicitly,
and it lets you vary their interaction
independently - Replace many-to-many interactions with
one-to-many interactions - If an object is changed, only need to change the
Mediator, but not the rest of the objects
141Example dialog box
- A dialog box has a number of widgets
- Buttons, menus, and entry fields
142Dependencies between widgets
- Select an option in one widget causes changes in
other widgets
143- Without mediator
- If a widget is changed, need to notify other
widgets - Creates dependency between widgets, tight
coupling, makes future change difficult - With mediator
- If a widget is changed, only need to notify the
Mediator - Loose coupling, localized change
- The Mediator centralizes control, to change the
behavior only requires subclassing the Mediator
144Mediator
145How to test your code
- A common generic pattern in testing
- Set up the environment
- Do some work
- Tear down
- TestCase()
- SetUp()
- while ( HasMore() )
- Run()
-
- TearDown()
-
146Template Method
- We have a fixed sequence of steps which are
invariant, though the implementation of each step
may change - We may carry out different testing, but the
sequence remains the same - Template pattern encapsulates the sequence of
business logic
147Template Method
- Base class defines the template of an algorithm,
deferring the implementation to subclasses - Subclasses redefine certain steps of an algorithm
without changing the algorithms structure
TestCase() SetUp() . . .
SetUp() . . .
148Note
- The template method TestCase() is non-virtual
- Cannot be overrided by the subclass
- So that the fixed sequence cannot be changed
- Methods inside the template are protected
- Intended to be overrided by the subclasses, but
are not opened to public
149Template Method
- We have seen it before in creating a maze
- Maze MazeGame.CreateMaze()
- Maze aMaze makeMaze()
-
- Room r1 makeRoom(1)
- Room r2 makeRoom(2)
- Door theDoor makeDoor(r1, r2)
- aMaze.addRoom(r1)
- aMaze.addRoom(r2)
- . . .
A template of creating a maze
150TCP (transmission control protocol) implementation
- Problem
- How to implement TCP?
- TCP is complex !!
- A connection can be in one of the many states
- e.g. Listen, Established, SynSent
- A connection may receive different requests
- e.g. active open, close, acknowledge
- Different state responds to the request
differently
151TCP state diagram
152State
- Listen, Established, Closed is-a kind of State
TCPState
SynSent
Established
Closed
153State
- Each TCPConnection has-a State
TCPConnection TCPState _state
TCPState
SynSent
Established
Closed
154State
- TCPConnection may receive many requests
- e.g. connect, close, acknowledge
TCPConnection Connect() Close() Acknowledge()
TCPState _state
TCPState
SynSent
Established
Closed
155Should TCPConnection handle the requests?
- No, requests are state-dependent
- Delegate the requests to the TCPState objects
TCPConnection Connect() . . . TCPState _state
TCPState Connect() . . .
SynSent Connect() . . .
Closed Connect() . . .
156How to handle a request?
- TCPConnection receives a connect request
- TCPConnection object delegates the request to
_state (the current TCPState object) - No ugly if-then-else block
157How to handle a request?
- class TCPConnection
- private TCPState _state //current state
- void Connect()
-
- _state.Connect(this) //delegate
-
- public void ChangeState(TCPState nextState)
-
- _state nextState
-
158To change the state of TCPConnection
- The concrete object TCPState does the work, then
use ChangeState() to change _state in
TCPConnection to next state - class TCPClosed TCPState
- void ActiveOpen(TCPConnection t)
- //. . . send SYN
- t.ChangeState(TCPSynSent.Instance)
-
Static property returning a Singleton of
TCPSynSent
159State
- For each concrete TCPState, only implement the
functions that is meaningful - Meaningless requests can be ignored
- Base class TCPState provides the dummy default
- A do-nothing dummy default
- public override void TCPState.Connect(TCPConnectio
n t)
160Singleton
- None of the TCPState subclass has local state
variables ! - If the objects are stateless (have no memory)
- Only need one object for each TCPState is enough
- Singleton
- Singleton object can be accessed directly
161Singleton
Singleton, shared by all connections
TCPListen
TCPClosed
. . .
socket
TCPConnection
TCPState
162Problem
- How to encapsulate an algorithm so that your
software can select between different algorithms
flexibly? - e.g.
- In word processing, choose between the different
output formatter (pdf, postscript, rtf) - In action game, fighters can have different
algorithm for different fighting level
163- Solution by subclassing
- But subclassing makes it difficult for an object
to change the algorithm at run time - The algorithm is statically binded to the
concrete object
Base Class void Algo()
Derived Class A void Algo()
Derived Class B void Algo()
164Strategy
- Object delegation
- the base class object is free to change the
strategy object at run time
Strategy void Algo()
Base Strategy _s void Algo() _s-gtAlgo()
Derived class A void Algo()
Derived class B void Algo()
165State and Strategy
- Same class diagram, same pattern of code !
- Differed by their intent and dynamics
- States intent
- Allow an object to alter its behavior when its
internal state changes -
- Strategys intent
- Define a family of algorithm, encapsulate each
one, and make them interchangeable
166Problem
- How to add new functionality to a system?
- e.g to add a print option to the registration
system - Solution
- Add Print() to the base class
Node Search() Print()
Course Search() Print() . . .
NodeList Search() Print() . . .
167Problem
- Modify the base class, violate the open-close
principle! - Solution
- Visitor Pattern
- Visitor lets you define a new operation without
changing the classes of the elements on which it
operates
168How it works
- Accept() is a general-purpose method that can
accept a Visitor object
Node Accept(Visitor v)
NodeList Accept(Visitor v) Node _list
Course Accept(Visitor v)
169Visitor Pattern
- A node accepts a visitor object
- Node.Accept(Visitor v)
- Node.Accept() immediately returns the call to
Visitor and pass itself as the argument - v.Visit(this) //thisthe current node
- Visitor.Visit(Node n) receives the node and does
something about it - e.g. print the node, search the node
170Code example
- If the concrete node is a Course object
- Course.Accept(Visitor v)
- v.Visit(this) //callback
-
- If the concrete node is a NodeList object
- NodeList.Accept(Visitor v)
- v.Visit(this) //process the list
- foreach (Node n in _list)
- n.Accept(v) //call each node in list
-
171Visitor Visit(Node n)
PrintVisitor Visit(Node n) //doSomething
SearchVisitor Visit(Node n) //doSomething
Node Accept(Visitor v)
client
Course
NodeList
172Note
- Node usually has a tree (composite) structure
- The visitor object transverses all nodes in the
tree - Each node callbacks to the visitor visitor
provides the new functionality - To add new functionality
- simply add a new subclass of visitor,
- no need to modify the object structure (Node)
173Visitor Pattern
- Refinement
- Both Course and NodeList make a callback to the
same visitor(Node n) method - Sometime we would like to treat callback from
Course and NodeList differently, - e.g. PrintCourseName visitor
- If callback from a Cours