Design Pattern in Simple Examples
Instead of defining what is design pattern lets define what we mean by design and what we mean by pattern. According to me design is blue print or sketch of something so it can be defined as creation of something in mind. Moving to pattern, we can define it as guideline, or something that repeats. Now the definition of design pattern becomes creating something in mind that repeats or in other words capturing design ideas as a "pattern" to the problems.
Some problem patterns happen over and over again in a given context and Design Pattern
provides a core of the solution in such a way that you can use the core
solution every time but implementation should and may vary and the main
reason behind that is we have the core solution and not the exact
solution. We can discuss an example here about database normalization.
Normalization is a pattern (Core solution to database design) but what
level of normalization you need (exact solution) depends on your
requirement and context.
In this article I will be discussing the following Design patterns ( or common problems and there common solutions which are time tested and have worked when applied ).
- Creational Patterns
- Structural Patterns
- Behavioral Patterns
I will not be defining the design patterns because you can always
find them in any standard book but I will be dealing with the actual use
and examples of them. To understand the article in a better I would
suggest you first download the demo project.
To see any sample you make the project as the StartUp project and
compile the project and execute it. The solution is build using
Microsoft Visual Studio 2005. I have purposely used the abstract classes
over interface so the class diagram of the samples looks exactly
similar to one suggested by gang of four. If you find a class whose Name
is IClassName please don't get upset but its done purposefully to make
the class diagrams. In the article I have tried to use as many pictures
as possible because "A picture is worth a thousand words"
Creational Patterns
Abstract Factory
- Do we need to create families of objects.
Factory method takes care of one product where as the abstract factory Pattern provides a way to encapsulate a family of products.
Typically the class diagram looks like
Example
We have a requirement where we need to create control library and the
same library supports multiple platforms but the client code should not
be changed if we import from one operating system to the other. The
solution is
The client uses the GuiFactory to get the required factory of the
supported operating system and calls the same Show Method. Now depending
on the platform we change the factory but the client implementation
remains the same. If support for new operating system is to be added we
need the new factory and the exact implementation of the buttons and
without changing the existing code we can support the new platform.
Builder
- Do we need to create object in several steps.
Builds a class based on requirements where Director asks the builder to
build each of the parts. Mainly the builder pattern is not used
independently but other patterns may have builder pattern as a part
where they create the complicated objects using the builder.
Typically the class diagram looks like
Example
Who is what?
Waiter is Director
PizzaBuilder is Builder
CheesePizzaBuilder and MixedPizzaBuilder are Concretebuilder
Pizza is product
When Waiter
(Director
) is asked to serve
it creates the Pizza
(Product
) using the PizzaBuilder
.
Another example could be Maze which is a complicated object build from walls and rooms.
Factory
- Do we need to have derived classes figure out what to instantiate and decouple client from instantiated class.
Client uses the factory to create products and its the factory which
decides when the actual product is needed for instantiation. This way
client decouples the instance and can be saved from some of the crucial
operations of object copy if the type of object may change after
creation.
Typically the class diagram looks like
Example
Who is what?
ComputerFactory (Creator
)
ConcreteComputerFactory (ConcreteCreator
)
Processor (Product
)
ConcreteProcessor (ConcreteProduct
)
When the GetProcessor
of ComputerFactory is called its the ConcreteComputerFactory
creates the ConcreteProcessor
and the creation of ConcreteProcessor
is delayed till we call the GetProcessor()
function.
Another good example could be logging, where we create the instance of
the logger factory but instantiate the logger class when actual logging
is done.
Prototype
- Do we have too many classes to instantiate / or is the object creation a cumbersome process.
Mainly we don't create the objects of a class directly but clone the
existing object and change the state of the object as needed. The main
application of such pattern is when the object creation is costly. As an
example we have a database class the constructor sets up the database
for the class. Now for each new user logging to the system once the
system is up we don't setup the database but just clone the first object
and change the user specific details like user name / password to
validate the user.
Typically the class diagram looks like
Example
I would not explain here who is what because its pretty much evident.
Singleton
- Do we need to limit the no of objects of a class.
Ensures only one (n = 1..n) instance. The pattern explains how you can
achieve the singleton class. It says to have the constructor as private
and have a static method to access the instance of the class using that
method.
Typically the class diagram looks like
Example
I would not explain here who is what because its pretty much evident.
Structural Patterns
Adapter
- Do we have the right stuff but wrong interface.
We use the adapter design pattern where the requirements is to convert
between one interface to another. Adapter pattern is never implemented
when designing a new system but with the changing requirements we have
deferring interfaces then adapter comes into picture.
Typically the class diagram looks like
Example
We have used some library where we have Add function which takes two
integer and provides the sum of them. Now when upgrading the libray we
find that the library has changed the Add function such that it takes 2
floating point number. Now one option could be to change all the client
code where we have used the Add method or other option is to have an
Adapter.
CalcAdapter calls the necessary library function after making the
necessary changes (in our example conversion between the data types)
Bridge
- Do we have one variation using another variation in a varying way.
Decouple an abstraction from its implementation so that two can vary
independently. In strategy pattern we decouple the behavior but in
Bridge we decouple the abstraction.
Typically the class diagram looks like
Example
In Abstract Factory
we discussed about the problem of creating a control library for
various operating system. Now creating the library from the scratch is
never a good idea and so we may need to use some of the existing
infrastructure or library available. We may use the XWindow toolkit or
MacWindow toolkit as the base depending on the user platform and toolkit
available.
The DrawRect actually uses the DrawLine function which actually is
dependent on the type of implementation and we seperate the
implementation from the abstraction and have a link ( or bridge )
between the two.
Composite
- Do we have units and groups and want to treat them the same way.
Compose the objects in a tree structure where individual objects as well
as the composed objects behave uniformly. Composed objects delegates
the requests to the individual leaf objects.
Typically the class diagram looks like
Example
We have some simple graphics and have some graphics which are composed
of these simple graphics and as a client both should behave uniformly.
Folder browsing could be other example where from the client's point of
view its an operation on the folder tree irrespective of its folder (
composite object ) or file ( leaf object ).
Decorator
- Do we need multiple additional functions we may need to apply, but which and how many we add varies, without sub classing.
Attach additional responsibilities to an object dynamically. It has the
capability of performing some additional operations before or after the
basic operation.
Typically the class diagram looks like
Example
Say we have a FileReader
class where the file can be read based on the combination of applying any of the formulas like it could be
- Zipped.
- Encrypted.
- Zipped and encrypted.
- encrypted then zipped and ecrypted again.
The solution is Decorator pattern where we apply the options based on the requirement.
Code: CSharp
// Zip the File
ZipReader zip = new ZipReader(file);
// Encrypt the zip file
EncryptedReader enc = new EncryptedReader(zip);
enc.Read();
Code: CSharp
// Encrypt the file
enc = new EncryptedReader(file);
// Zip the encrypted file
zip = new ZipReader(enc);
zip.Read();
We can apply any combination as and when needed and also new methods of
encryption is very simple. Just add the new class as sibling of EncryptedReader
Facade
- Do we want simplify, beautify or OO-fy an existing class or subsystem.
When client is decoupled from the system using an inter mediator its
called facade. Facade behaves as a door to subsystem and provides a
single interface to complex interface in the subsystem. Here a point to
note is that the subsystem should not have a dependency on the FACADE
and if thats the case then the facade is a part of the sub-system and it
should move into the sub-system and we should have a new facade class.
Also Facade is not the only entry point to the sub-system but is a
convenient point of communication to the subsystem and client can always
have the direct access to the subsystem.
This methods helps in developing the subsystem independently without affecting the clients using them.
Typically the class diagram looks like
Example
We have a Car System creation where the car is created based on the complex subsystems like wheel, steering, chassis, body ...
Flyweight
- Do we have too many part objects.
Any objects state can be classified into two types of data that it can
store one is intrinsic (static and independent of object) and one is
extrinsic (non-static and depend on the state of the object) then
flyweight pattern can be applied. The design pattern is useful when we
have large no of objects which can be grouped once the extrinsic state
is removed and it uses de-encapsulation to split the objects.
Typically the class diagram looks like
Example
We have some shape objects and the shape objects are really costly and
so we can have the shape object split itself such that some data which
is independent of the state of the object is kept in the object and
other data is provided externally. Say in our shape object how the shape
is drawn is same but where the shape is drawn is dependent on the state
of the object and so the print method should know where to print which
is extrinsic and should be supplied.
Proxy
- Do we need
to optionally add some new functionality to something that already
exists. Do we need to control how an object is accessed.
It provides a placeholder for another objects and the proxy object gives
the impression to the client that actual request is handled by the
proxy but it just delegates the request to the real subject.
Typically the class diagram looks like
Example
Say we have a system setup where we send and receive data over the
network. Now due to some security reasons data are encrypted and so now
they need to be decrypted before processing and so now we are in trouble
because all the client code needs to be changed to decrypt the data or
we may need to change the stable library code which use to send/recieve
the data. Now the solution could be to have the proxy which will do the
additional responsibility given to the system and then send the data
using the well tested system in place.
We should be using the proxy system where we think we may need to add some additional responsibilities later.
Behavioral Patterns
Chain of Responsibility
- Do we have diff. objects that can do the job but we do not want the client object know which is actually going to do it.
Avoid coupling the sender of a request to its reciever by giving more
than one object a chance to handle the request. Helps in reducing the
coupling though they are chained, but does not know about other objects
apart fron the fact that they derive from the common interface.
Best example could be Context help where the each help component tries
to perform the request and when fail they pass the request in the chain
to other members.
Typically the class diagram looks like
Example
In the banking system where cheque's for clearing is approved by the
person but if the cheque amount is beyond certain limit, the approving
responsibility moves the person higher in authority in the bank.
Windows messaging system works in the similar method where the messages
are processed by the controls if the point likes with the bounds of the
control or goes to the parent.
Command
- Do we need to decouple request from handler.
Encapsulate requests for service from an object inside other object(s)
and manipulate requests. Command objects are mainly helpful in undo/redo
operation where the previous state can be saved for reloading or even
the necessary command(s) can be stored in stack for the same.
Typically the class diagram looks like
Example
Say we have designed an image editor and user can have the option of
opening file from various ways like menu, tool bar, double click on a
file in the explorer. The solution is the command pattern where the FileOpen
command is associated in the viewer itself and when the command executes the file is shown in the viewer.
The other example could be the operations on the images.
Interpreter
As the name suggest it interpret your expression. Some expressions are
atomic and some complex which are made up of atomic and it interprets
the atomic and complex expressions uniformly. It mainly uses in the
compilers / parsers / Macro expansions.
I have not provided any sample because this one is not that often used
just for completeness of the article have mentioned the pattern here.
Iterator
- Do we want to separate collection from client that's using.
Provide a way to access the elements of an aggregate objects
sequentially without exposing its representation. We can make the client
independent on the movement of the cursors like forward traversal /
backward traversal as well as the internal implementation of the list.
Typically the class diagram looks like
Example
I would not explain here who is what because its pretty much evident and
nowadays any modern language supports this and so you could use the foreach
loop. In C-Sharp if you would like to have a class that will be a list you need to use the IEnumerator
and IEnumerable
interfaces and then it will support the foreach
loop.
List should implement IEnumerable and the Iterator should implement IEnumerator.
Mediator
- Do we have a lot of coupling in who must talk to whom.
Define objects in the subsystem where the set of objects interact. This
pattern is much similar to the Facade but in facade the sub-system knows
nothing about the Facade but here the sub-system communicate through
the mediator and the client also communicate through the mediator.
Mediator hides the complicated communication in the subsystem where as
facade sub-system classes are open to the client as well, So Facade is
an optional point of communication where as Mediator is only point of
communication to the subsystem.
Typically the class diagram looks like
Example
Now don't blame me if for the third time I take the example of the
control library where we have a dialog and some controls over the
dialog. The controls can be interacted through the DialogMediator
. Now if the siblings of the Dialog would like to interact they do so through the DialogMediator
because its the DialogMediator
who has the information about the rest of the sub-system
Memento
Delegate some activity to some other class like some helper classes to do the job.
The memento pattern is used to encapsulate the current state of an
object in a memento object in order to be able to restore the object
state later without exposing the internal representation of the object
to the outside world. The memento pattern is useful when you have an
object which you would to take a "snapshot" of so that at a later time
you could use the snapshot to restore it to its original state, such as
an undo or rollback operation.
Typically the class diagram looks like
Example
Suppose you have a an object which stores form information and you would
like to allow the user to make changes in the form and then if they
make a mistake later you can put back in the original form values. Well,
you could serialize the form object and then un-serialize it later but
this is obviously messy and not a good solution. Another possible
solution would be to have an outside object use the form's accessors
methods to pull out what you need to save the state but this causes high
coupling between the class saving the state and the form; any changes
in the form would require changes in the other class. We need something
that will allow you to save the state and restore it later without
having to get involved in the details. This is where the memento pattern
comes in.
Observer
- Do various entities need to know about events that have occurred? How to keep dependent object up-to-date.
When we have one to many dependency between objects so when the object
changes, its dependents are notified of the update automatically. The
best example is something like Excel with data in one cells and we have
multiple charts which gets updated when there is change in the data.
This design pattern is more useful if we have one sided broadcast
communication and is useful when we have one to many relationship.
Typically the class diagram looks like
Example
When any data is changed in the XMLDoc
object it calls the Notify
Method of the base class which has the list of the active observers attached to the XMLDoc
and calls the Update
method of all the view of the data.
State
- Do we have a system with lots of states where keeping track of code for differrent states is difficult.
Allow the object to alter it behavior when its internal state change.
Typically the class diagram looks like
Example
We have a Printer system where we have the following states for the
printer and based on the actions taken in particular state, the state of
the printer changes accordingly.
Instead of having the state defined in the printer itself we keep the
state of the printer into separate object and separate the
responsibilities. "Have objects for state."
Strategy
- Do we have a varying rule or algorithm.
Define a family of algorithms, encapsulate each one and make them
interchangeable. It allows us to change the algorithm independently with
out changing the client using it. It converts the generalization of the
template method to composition or aggregation.
It has various uses like it allows the algorithm to vary frequently and is a very good alternate solution to sub-classing.
Typically the class diagram looks like
Example
We have a payment system where we have an Invoice class where we
calculate the total of the amount payable but the requirement is such
the amount calculation depends on the type of customer and discount
offer. Also over the time the offers / discount may differ and may need
to change the offer at run-time. The solution is
Now if have some special offer coming for the season sale all we need to do is add a new class derived from NetPayable
and then add the necessary calculation logic in that class and this way we can have the new algorithm added dynamically.
Template Method
- Do we have a skeleton of the algorithm and want to leave upto the sub classes how each step behaves.
Define the skeleton of the algorithm in an operation and deferring the
exact implementations of the steps of the algorithms to its subclasses.
Template method uses the HR policy of "we will call you" which means the
exact implementations of the algorithm will be called by the base
class.
Typically the class diagram looks like
Example
Printing algorithm for various types of documents where the algorithm is
fixed of printing the header then body and at last the footer which is
defined in the base class the exactly how the headers are printed is
defined in the supported document classes.
Visitor
- Do we have new tasks that we will need to apply to our existing classes.
Represent an operation to be performed on the element of an object and
helps you add new methods to existing hierarchy without affecting the
existing hierarchy. This also de-encapsulate where we break the class so
that some future functionality can be added but it has the disadvantage
that concrete elements cannot be added without changing the interface.
Use of the pattern should be done if you have the concrete elements
fixed but you may need to add the new functionality to the existing
object.
Typically the class diagram looks like
Example
We have the number of objects supported in the drawing system fixed but
we need to add the depth in the way the object does it operations like
scale or drawing of the object. We could have the same class do both the
job but we need some specialist in the field doing the job. A
mathematician is good at doing the scaling but not at drawing or vice
versa and so here we use the visitor pattern.
Accept method actually calls the correct implementation based on the
visitor passed, so its the client who tells if he needs to draw or
scale.
GOLDEN RULE(s) of design pattern
- Client should always call the abstraction (interface) and not the exact implementation.
- Future changes should not impact the existing system.
- Change always what is changing.
- Have loose coupling
- Inheritance ( Very coupled )
- Composition
- Aggregation
- Association
- Dependency
- Realization ( Least couple )