2. Objective
What principles and patterns are and why they are critical to implement applications
successfully
Understand and apply the principles of object-oriented design
Understand GRASP patterns
Understand important design patterns
4. Why Design Principles?
All systems change during their life cycle.
Symptoms of Rotting Design
There are 4 primary symptoms that tell us that our designs are rotting.
Rigidity
It is hard to change because every change affects too many other parts of the system
Fragility
When you make a change, unexpected parts of the system break
Immobility
It is hard to reuse in another application because it cannot be separated from the current
application
Viscosity
Design – Engineers usually find more than one way to make change. Some preserve the design and
others do not. When the design preserving methods are harder to employ then the viscosity of the
design is high
Environment – Development environment is slow and inefficient (e.g. compile times are very long)
engineers will be tempted to make changes that don’t force large compiles, even though those
changes are not optimal from design point of view
5. Why Design Principles?
Changing Requirements
Immediate cause of the degradation of the design
Requirements have been changing in way that the initial design did not anticipate
These changes need to be made quickly, and may be done by others who are not familiar
with the original design philosophy
Changes to the original design somehow violates the original design bit by bit as the changes
continue to pour in, these violations accumulate until malignancy sets in
We, as software engineers should keep in mind that requirements change
If our designs are failing due to the constant rain of changing requirements, it is our designs
that are at fault
Find a way to make our design resilient to such changes and protect from rotting
Any application that exhibits these symptoms is suffering from a design that is rotting from
the inside out.
But what causes that rot to take place ?
6. Why Design Principles?
What kind of changes cause design to rot ?
Dependency Management
Changes that introduce new and unplanned for dependencies
Four symptoms mentioned earlier is either directly, or indirectly caused by improper dependencies
between the modules of the software
It is the dependency architecture that is degrading
In order to forestall the degradation of the dependency architecture, the dependencies between modules
in an application must be managed
This management consists of the creation of dependency firewalls
So what is the solution ?
Object Oriented Design is supplied with principles and techniques for building such firewalls, and
for managing module dependencies.
7. Design Principles
Software design principles represent a set of guidelines that helps us to avoid
having a bad design as mentioned earlier.
8. Key Design Principles
SOLID
Is a acronym introduced by Robert C Martin
Stands for five basic principles of object-oriented programming design
Initial Stands for
(acronym)
Concept
S SRP Single Responsibility Principle
O OCP Open Closed Principle
L LSP Liskov Substitution Principle
I ISP Interface Segregation Principle
D DIP Dependency Inversion Principle
Other
Composite Reuse Principle
Law of Demeter
9. Single Responsibility Principle (SRP)
What
Single responsibility principle states that every object should have a single responsibility
and therefore a single reason to change
A class should have only one reason to change
12. Conclusion
Single responsibility principle (SRP)
Why
Single Responsibility - increased cohesion
Readability – easier to read as it performs one task
Testability – only one thing to test
Reusability – class is easier to reuse
Easier to code – easier and faster to code in small chunks
Bugs – become easier to track down
One of the simplest of the principles
Hardest to get it right
A good way of separation of responsibilities
Separation of those responsibilities from one another is much of what software design is
really about
13. Open Close Principle (OCP)
What
The Open Close Principle states that the design and writing of the code should be done in a way
that new functionality should be added with minimum changes in the existing code
Software entities like classes, modules and functions should be open for extension
but closed for modifications.
The design should be done in a way to allow the adding of new functionality as new classes,
keeping as much as possible existing code unchanged
15. Example
Open Close Principle (OCP)
Imagine few months down the line you got tired of drinking only Coke and Pepsi and wants
to add sprite?
16. Conclusion
Open Close Principle (OCP)
Why
Open for extension – behavior of the module/class can be altered to satisfy the changing
requirements
Closed for modification – modules/classes themselves are not allowed to change
Maintainable – module is maintainable as it never needs to change
Reusability – module/class being open for extension, it is highly reusable
Flexible design involves additional time and effort spent for it and it introduce new level
of abstraction increasing the complexity of the code
So this principle should be applied in those area which are most likely to be changed
17. Liskov’s Substitution Principle (LSP)
What
The LSP states that if a program (User) module is using a Base class, then the reference to the Base class
can be replaced with a Derived class without affecting the functionality of the program module.
Functions that use references to base (Super) classes must be able to use
objects of derived (Sub) classes without knowing it
All derived classes must honour the contracts
of their base classes
ISA = same public behavior
Pre-conditions can only get weaker
Post-conditions can only get stronger
18. Example
Liskov’s Substitution Principle (LSP)
Whether Square is a Rectangle?
class LspTest
{
private static Rectangle getNewRectangle()
{
// it can be an object returned by some factory ...
return new Square();
}
public static void main (String args[])
{
Rectangle r = LspTest.getNewRectangle();
r.setWidth(5);
r.setHeight(10);
// user knows that r it's a rectangle. It assumes that he's able to set the width and height as
for the base class
System.out.println(r.getArea());
// now he's surprised to see that the area is 100 instead of 50.
}
}
Rectangle
+setHeight() : void
+setWidth() : void
Square
+setHeight() : void
+setWidth() : void
19. Example
Liskov’s Substitution Principle (LSP)
What if the minimum period for SpecialCurrentAccount is not satisfied?
The closing of Current Account should check for a balance
greater than zero. If satisfied, proceed to close the account.
The closing of Special Current Account should check for a
balance greater than zero and also that the minimum period for
the account is covered. If satisfied, proceed to close the account.
period
closeAccount() : void
20. Conclusion
Liskov’s Substitution Principle (LSP)
Why
OCP violations - if / else to identify types
Unit tests – Unit tests for the super class would never succeed for the sub class
Strange behavior - Mess being that whenever a subclass instance was passed as parameter
to any method, strange behavior would occur
This principle is just an extension of the Open Close Principle and it means that we must
make sure that new derived classes are extending the base classes without changing their
behavior
Basically wants you to think clearly about the expected behavior and expectations of a
class before you derive new classes from it
21. Interface Segregation Principle (ISP)
What
The Interface Segregation Principle states that clients should not be forced to implement
interfaces they don't use. Instead of one fat interface many small interfaces are preferred based
on groups of methods, each one serving one sub module.
Make fine grained interfaces that are client specific
23. Example
Interface Segregation Principle (ISP)
What if there is a need to rotate the file data source to a different file once a
certain amount of data has been written to the file?
24. Conclusion
Interface Segregation Principle (ISP)
Why
High cohesion – Keep all related methods together
Low Coupling – Keep dependence of one another to the bare minimum
Fat interfaces – tend to cause a ripple affect to classes who shouldn’t have been affected
in the first place
It produces a flexible design. If we are going to apply it more than is necessary it will result
a code containing a lot of interfaces with single methods, so applying should be done
based on experience and common sense in identifying the areas where extension of code
are more likely to happens in the future.
25. Dependency Inversion Principle (DIP)
What
Depend on Abstractions. Do not depend on Concrete implementations
Design towards Interfaces/Abstract classes rather its implementations.
Since implementations are more prone to change and offer less flexibility.
High Level Classes --> Abstraction Layer --> Low Level Classes
According to this principle the way of designing a class structure is to start
from high level modules to the low level modules
28. Conclusion
Dependency Inversion Principle (DIP)
Why
Increase loose coupling
Abstract interfaces don't change
Concrete classes implement interfaces
Concrete classes easy to throw away and replace
Increase mobility
Increase isolation
Decrease rigidity
Increase testability
Increase maintainability
This principle can not be applied for every class or every module. If we have a class
functionality that is more likely to remain unchanged in the future there is no need to
apply this principle.
29. Composite Reuse Principle (CRP)
What
Favor delegation over inheritance as a reuse mechanism
The Composite Reuse Principles focuses on achieving reuse through delegation (or more
appropriately forwarding), instead of defining default behaviors in ancestor classes.
30. Example
Composite Reuse Principle (CRP)
Subclasses of Employee: Manager,
Programmer, Secretary, etc. may want to
override this method to reflect the fact
that some types of employees
(managers) get more generous bonuses
than others
. . . .
Employee
+computeBonus() : Money
Manager
+computeBonus() : Money
What if we wanted to
change the bonus
computation for a
particular employee
33. Conclusion
Composite Reuse Principle (CRP)
Why
This principle relies heavily upon delegation, or more appropriately forwarding.
Composite Reuse Principle helps us comply with the Open Closed Principle.
Composite Reuse Principle is typically used in conjunction with Dependency Inversion, though
this is not a requirement.
This is where Composition is a superior choice. Inheritance ties you to a particular
implementation or forces you to give up the original idea of generalization by having to
constantly override the super-class methods in each sub-class.
34. Law of Demeter
What
Restrict class interaction in order to minimize coupling among classes
More formally, the Law of Demeter for functions requires that a method M of an object O may
only invoke the methods of the following kinds of objects:
O itself (this)
M's parameters
any objects created/instantiated within M
O's direct component objects
a global variable, accessible by O, in the scope of M
Also called as Principle of Least Knowledge (PLK)
“Each unit should only talk to its friends.” “Don’t talk to strangers
35. Example
Law of Demeter
An alternative to PLK, or a variation on its implementation, is to obtain a reference to an
object via a method call, with the restriction that any time this is done, the type of the
reference obtained is always an interface data type.
36. Example
Law of Demeter
What if currentPerson.Account = null ?
currentPerson.Account.Deposit(500)
Account may need to be initialized before it can be accessed Say currentPerson.Account =
null, will throw null reference exception in bad code
In good code, Deposit method can check if null and setup a new one before depositing
Account.Deposit(currentPerson, 500)
37. Conclusion
Law of Demeter
Why
The advantage of following the Law of Demeter is that the resulting software tends to be
more maintainable and adaptable.
Since objects are less dependent on the internal structure of other objects, object
containers can be changed without reworking their callers.
A disadvantage of the Law of Demeter is that it sometimes requires writing a large
number of small “wrapper” methods to propagate method calls to the components.
The higher the degree of coupling between classes, the higher the odds that any change
you make will break something somewhere else. This tends to create fragile, brittle code.
39. Why design patterns ?
Developing software is hard, and developing reusable design is even harder
Helps in software quality, reduce the development time and improves the shared
understanding with in development team
Design Pattern = Proven solution to problems for the specific context
How do you master these patterns?
Simple!! learn rules of the language, then principles/best practices, finally study the patterns
used by other masters. Apply these understanding repeatedly in your problem context
There are hundreds of patterns do exist in software industry, one must have maturity of selecting
appropriate pattern for the context. Care must be taken of applying unnecessary pattern ahead
of requirements which would have been solved without it.
40. Evolution of Patterns
It all started in civil engineering and architecture
Design patterns originated outside the computer industry
Design patterns are discovered as much as created
41. What is pattern ?
Pattern describes a proven solution to a recurring design problems
Solution to a problem in a given context
A Pattern is common, repeatable solution
Patterns are generic and take many forms
It is advice from previous designers to help designers in new situations
Patterns capture the static and dynamic structure and collaboration among key
participants in software designs
Patterns facilitate reuse of successful software architectures and designs
42. Design patterns definitions
“A pattern is a proven solution to a problem in a context “
-
“Each 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, without doing it the same way twice.”
- By Alexander
“A pattern is a three-part rule, which expresses a relation between a certain context, a
problem, and a solution”
- By Gang of Four (GoF)
(Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides – GoF)
43. Properties of patterns
Patterns do...
provide common vocabulary
provide “shorthand” for effectively communicating complex principles
help document software architecture
capture essential parts of a design in compact form
show more than one solution
describe software abstractions
Patterns do not...
provide an exact solution
solve all design problems
only apply for object-oriented design
44. Identifying a pattern
Identify patterns from experience
Look at your past projects
Analyse good performing applications
Identify pattern candidates
Verify the pattern thoroughly
45. Using design patterns
Understand it completely
Check twice before using
Study carefully the examples for the pattern
Choose names for the pattern participants that are meaningful for
your application
Define the interfaces, components, classes and relationship
Apply the pattern
Be careful of Antipatterns
49. GRASP Patterns
GRASP stands for General Responsibility Assignment Software Patterns/Principles.
- Craig Larman
Responsibility
“A contract or obligation of a type or class”
Two types of responsibilities
- knowing
- doing
• about private encapsulated data
• about related objects
• things that can derive or calculate
• something itself
• initiating action in other objects
• controlling and coordinating activities in other
objects
50. GRASP Patterns
Which class, in the general case is responsible?
You want to assign a responsibility to a class
You want to avoid or minimize additional dependencies
You want to maximise cohesion and minimise coupling
You want to increase reuse and decrease maintenance
You want to maximise understand ability
…..etc.
51. GRASP Patterns
There are nine (09) core patterns/principles
Information Expert
Creator
Controller
Low Coupling
High Cohesion
Polymorphism
Pure Fabrication
Indirection
Protected Variations
52. Information Expert
Assign a responsibility to the information expert
- the class that has the information necessary to fulfill the responsibility.
The most commonly used pattern
Problem:
What is the most basic principle by which responsibilities are assigned in object-oriented
design?
Solution:
Assign a responsibility to the class that has the information necessary to fulfil the
responsibility.
53. Example
Information Expert
Who is responsible for knowing the grand total of a sale in a typical Point of Sale application?
Sale
date
time
Sales
LineItem
quantity
Product
Specification
description
price
UPC
Described-
by
*
Contain
s
1.. *
54. Need all SalesLineItem instances and their subtotals. Only Sale knows this, so Sale is the
information expert.
Example : Answer
Information Expert
Hence
Sale
date
time
total()
:Salet :=total()
Newmethod
But subtotals are needed for each line item (multiply quantity by price). By Expert,
SalesLineItem is expert, knows quantity and has association with ProductSpecification
which knows price.
55. Example : Answer
Information Expert
Sale
date
time
total()
:Salet := total()
sli:SalesLineItem
SalesLineItem
quantity
subtotal()
2: st :=subtotal()
:Product
Specification
2.1: p := price()
Product
Specification
description
price
UPC
price()Newmethod
SalesLineItem
:SalesLineItem
1*: [foreach]sli :=next()
56. Information Expert
Hence responsibilities assign to the 3 classes.
Class Responsibility
Sale knows sale total
SalesLineItem knows line item subtotal
ProductSpecification knows product price
58. Creator
By creator, assign class B responsibility of creating instance of class A if
B aggregates A objects
B contains A objects
B records instances of A objects
B closely uses A objects
B has the initializing data for creating A objects
Who has responsibility to create an object?
Problem:
Assign responsibility for creating a new instance of some class?
Solution:
Determine which class should create instances of a class based on the relationship between
potential creator classes and the class to be instantiated.
59. Example
Creator
Who is responsible for creating SalesLineItem objects?
Sale
date
time
Sales
LineItem
quantity
Product
Specification
description
price
UPC
Described-
by
*
Contain
s
1.. *
Look for a class that aggregates or contains SalesLineItem objects.
60. Example
Creator
Creator pattern suggests Sale.
Collaboration diagram is
Sale
date
time
makeLineItem()
total()
:SalemakeLineItem(quantity)
:SalesLineItem
1:create(quantity) Newmethod
61. Creator
Promotes low coupling by making instances of a class responsible for creating
objects they need to reference
By creating the objects themselves, they avoid being dependent on another
class to create the object for them
Why
62. Controller
Assign the responsibility for handling a system event message to a class representing one of
these choices:
1. The business or overall organization (a façade controller).
2. The overall "system" (a façade controller).
3. An animate thing in the domain that would perform the work (a role controller).
4. An artificial class (Pure Fabrication representing the use (a use case controller).
The Controller pattern provides guidance for generally acceptable choices.
Problem:
To assign responsibility for handling a system event?
Solution:
If a program receive events from external sources other than its graphical interface, add an
event class to decouple the event source (s) from the objects that actually handle the events.
64. Example
Controller
By controller, we have 4 choices
The overall system Post
The overall business Store
Someone in the real world
who is active in the task Cashier
An artificial handler of all system
events of a use case BuyItemsHandler
:POSTenterItem(upc,quantity)
:StoreenterItem(upc,quantity)
:CashierenterItem(upc,quantity)
:BuyItemsHandlerenterItem(upc,quantity)
The choice of which one to use will be influenced by other factors such as cohesion and
coupling
65. Example :
Controller
- presentation layer coupled to problem domain
Object Store
Enter Item End Sale
UPC
Make Payment
Total
Quantity
Tendered Balance
Cashier
:POSTCommand
presses button
onEnterItem()
:Sale
1:makeLineItem(upc,qty)
PresentationLayer
(Commandobject)
DomainLayer
Itisundesirableforapresentation
layerobjectssuchasaJavaappletto
getinvolvedindecidinghowtohandle
domainprocesses.
Businesslogicisembeddedinthe
presentationlayer,whichisnotuseful.
POSTAppletshouldnot
sendthismessage.
Bad design
66. Example
Controller
- presentation layer decoupled from problem domain
Object Store
Enter Item End Sale
UPC
Make Payment
Total
Quantity
Tendered Balance
:POST
Cashier
:POSTCommand
presses button
onEnterItem()
1:enterItem(upc,qty)
:Sale1.1:makeLineItem(upc,qty)
PresentationLayer
(CommandObject)
DomainLayer
systemeventmessage
controller
Good design
67. Controller
Using a controller object keeps external event sources and internal event
handlers independent of each other’ type and behavior
The controller objects can become highly coupled and uncohesive with more
responsibilities
Why
68. Low Coupling
Assign responsibilities so that (unnecessary) coupling remains low.
How to reduce the impact of change ?
Problem:
To support low dependency and increased reuse?
Solution:
Assign responsibilities so that coupling remains low.
Use this principle to alternatives.
69. Low Coupling
In object oriented languages, common form of coupling from TypeX to TypeY include:
TypeX has an attribute (data member or instance variable) that refers to a TypeY instance, or
TypeY itself
TypeX has a method which references an instance of TypeY, or TypeY itself, by any means.
These typically include a parameter or local variable of type TypeY, or the object returned
from a message being an instance of TypeY
TypeX is a direct or indirect subclass of TypeY
TypeY is an interface, and TypeX implements that interface
70. Low Coupling
How can we make classes independent of other classes?
Changes are localised
Easier to understand
Easier to reuse
Payment POST Sale
Who has responsibility to create a payment ?
71. Low Coupling
Two possibilities:
:POST p :Payment
:Sale
makePayment() 1:create()
2: addPayment(p)
1. Post
2. Sale :POST :Sale
:Payment
makePayment() 1:makePayment()
1.1.create()
Low coupling suggests Sale because Sale has to be coupled to Payment anyway (Sale knows its total).
1 Or 2 ?
Example
73. High Cohesion
Assign responsibilities so that cohesion remains high.
How to keep object focused, understandable, and manageable, and as a side-effect , support
low coupling ?
Problem:
To keep complexity manageable?
Solution:
Assign responsibilities so that cohesion remains high.
Use this principle to alternatives.
74. High Cohesion
Some examples
Very Low Cohesion: A Class is solely responsible for many things in very different
functional areas
Low Cohesion: A class has sole responsibility for a complex task in one functional area
High Cohesion. A class has moderate responsibilities in one functional area and
collaborates with classes to fulfil tasks
75. High Cohesion
Example
Who has responsibility to create a payment?
1.Post
:POST p : Payment
:Sale
makePayment() 1: create()
2: addPayment(p)
Looks OK if makePayement considered in isolation, but adding more system operations, Post
would take on more and more responsibilities and become less cohesive.
76. High Cohesion
Example
Giving responsibility to Sale supports higher cohesion in Post, as well as
low coupling.
:POST :Sale
:Payment
makePayment() 1: makePayment()
1.1.create()
77. High Cohesion
Classes are easier to maintain
Easier to understand
Often support low coupling
Supports reuse because of fine grained responsibility
Why
78. Polymorphism
When related alternatives or behaviours vary by type (class), assign responsibility for the
behaviour using polymorphic operations to the types for which the behaviour varies.
Who is responsible when behaviour varies by type ?
Problem:
To handle alternatives based on types?
Solution:
When alternate behaviours are selected based on the type of an object, use polymorphic
method call to select the behaviour, rather than using if statement to test the type.
79. Polymorphism
Example
By Polymorphism, each
payment should
authorize itself
CreditPayment
authorize()
CheckPayment
authorize()
CashPayment
authorize()
Payment
amount
In the point -of -sale application, who should be responsible for authorising different
kinds of payments?
80. Polymorphism
Easier and more reliable then using explicit selection logic
Easier to add additional behaviors later on
Increased number classes in a design
May make the code less easier to follow
Why
81. Pure Fabrication
Assign a highly cohesive set of responsibilities to an artificial or convenience “behaviour”
class that does not represent a problem domain concept–something made up, in order to
support high cohesion, low coupling, and reuse.
Who is responsible when you are desperate, and do not want to violate high cohesion and
low coupling?
Problem:
Not to violate High Cohesion and Low Coupling?
Solution:
Assign a highly cohesive set of responsibilities to an artificial class that does not represent
anything in the problem domain, in order to support high cohesion, low coupling, and reuse.
82. Pure Fabrication
Example
Suppose, in the point of sale example, that support is needed to save Sale instances in a relational
database. By Expert, there is some justification to assign this responsibility to Sale class.
However.
• The task requires a relatively large number of supporting database-oriented operations
and the Sale class becomes in cohesive.
• The sale class has to be coupled to the relational database increasing its coupling.
• Saving objects in a relational database is a very general task for which many classes need
support. Placing these responsibilities in the Sale class suggests there is going to be poor
reuse or lots of duplication in other classes that do the same thing.
83. Pure Fabrication
Example
The Sale remains well design, with high cohesion and low coupling
The PersistentStorageBroker class is itself relatively cohesive
The PersistentStorageBroker class is a very generic and reusable object
PersistentStorageBroker
save()
By Pure Fabrication
84. Pure Fabrication
High cohesion is supported because responsibilities are factored into a class that only
focuses on a very specific set of related tasks
Reuse potential may be increased because of the presence of fine grained Pure Fabrication
classes
Preserves low coupling and high cohesion of classes
Improve reusability of classes
Why
85. Indirection
Assign responsibilities to an intermediate object to mediate between other components
or services, so that they are not directly coupled.
How to assign responsibilities to avoid direct coupling ?
Problem:
To avoid direct coupling?
To de-couple objects so that Low coupling is supported and reuse potential remains high?
Solution:
Assign the responsibility to an intermediate object to mediate between other components or
services, so that they are not directly coupled.
86. Indirection
Example
PersistentStorageBroker
The Pure fabrication example of de-coupling the Sale from the relational database services through
the introduction of a PersistentStorageBroker is also an example of assigning responsibilities to
support Indirection. The PersistentStorageBroker acts as a intermediary between the Sale and
database
90. Protected Variations
Identify points of predicted variations or instability; assign responsibilities to create a
stable “interface” around them.
How to assign responsibilities to objects, subsystems, and systems so that the variations or
inability in these elements do not have an undesirable impact on other elements ?
Problem:
How to design objects so that variation or instability does not have an undesirable impact on
other elements?
Solution:
Identify points of predicated variation or instability; assign responsibilities to create a stable
interface around them
91. Protected Variations
Core mechanisms for Protected Variations
– Data encapsulation
– Interfaces
– Polymorphism
– Indirection
– Standards (e.g. APIs like JDBC)
• Note that these include virtual machines hiding OS, DB, network, etc
92. Protected Variations
Example
Adaptor
How to resolve incompatible interfaces or provide a stable interface to stable components with
different interfaces?
Convert the original interface of the component into another interface, through an intermediate
adaptor object
It is concept achieved through polymorphism, interfaces and indirection
93. Protected Variations
Example
Among other examples are JDBC and ODBC:
These are packages that allow applications to access databases in a DB-independent way
In spite of the fact that databases all use slightly different methods of communication
It is possible due to an implementation of Protected Variations
Users write code to use a generic interface
An adapter converts the generic method calls to DB-specific communications and vice versa
94. Protected Variations
Why
Protected variations addresses the problem of assigning responsibilities in such a way
that variations that might occur do not have undesirable effects upon other elements
in the system.
96. Core Design Patterns Classification
Creational Patterns
Have to do with class instantiation
Divided into class creation and object creation
Class creation patterns use inheritance effectively
Object creation patterns use delegation
Structural Patterns
Concern class and object composition
Use inheritance to compose interfaces
Define ways to compose objects to obtain new functionality
Behavioral
Specifically concerned with communication between objects
The Gang of Four (GoF) patterns are generally considered the foundation patterns. There are 23 core design
patterns identified by GoF.
97. Core Design Patterns Catalog
Purpose
Creational Structural Behavioral
Scope Class Factory Adapter Interpreter
Object Abstract Factory
Singleton
Builder
Prototype
Bridge
Composite
Decorator
Facade
Flyweight
Proxy
Chain of Responsibility
Command
Iterator
Mediator
Memento
Observer
State
Strategy
Template
Visitor
Defer object creation to
another class
Defer object creation to
another object
Describe algorithms and
flow control
Describe ways to
assemble objects
Important patterns
98. Factory
The Factory pattern provides a way to use an instance as a object factory. The factory can return
an instance of one of several possible classes (in a subclass hierarchy), depending on the data
provided to it.
99. Factory
Where to use
When a class can't anticipate which kind of class of object it must create
You want to localize the knowledge of which class gets created
When you have classes that is derived from the same subclasses, or they may in fact be
unrelated classes that just share the same interface. Either way, the methods in these class
instances are the same and can be used interchangeably
When you want to insulate the client from the actual type that is being instantiated.
100. Factory
Example The Connection object in the java package sql is a
factory.
Depending on the database driver you use you
get the database vendors implementation of the
Statement interface.
101. Factory
Why
The client does not need to know every subclass of objects it must create. It only need one
reference to the abstract class/interface and the factory object.
The factory encapsulate the creation of objects. This can be useful if the creation process is
very complex
Drawbacks/consequences
Gives subclasses a hook for providing an extended version of an object being constructed
There is no way to change an implementing class without a recompile
102. Abstract Factory
Abstract Factory offers the interface for creating a family of related objects, without explicitly
specifying their classes.
AbstractFactory
Declares an interface for operations that creates
abstract products.
ConcreteFactory
Implements operations to create concrete products.
AbstractProduct
Declares an interface for a type of product objects.
Product
It implements the AbstractProduct interface. Defines
a product to be created by the corresponding
ConcreteFactory.
Client
Uses the interfaces declared by the AbstractFactory
and AbstractProduct classes
103. Abstract Factory
Where to use
When the system needs to be independent of how its products are created composed and
represented
When the system needs to be configured with one of multiple families of products
When a family of products need to be used together and this constraint needs to be
enforced
When you need to provide a library of products, expose their interfaces not the
implementation
105. Abstract Factory
Why
Use of this pattern makes it possible to interchange concrete classes without changing the
code that uses them, even at runtime
Isolates concrete classes
Allows to change product family easily
Promotes consistency among products
Drawbacks/consequences
As with similar design patterns, one of the main drawbacks is the possibility of unnecessary
complexity and extra work in the initial writing of the code
106. Singleton
The Singleton pattern provides the possibility to control the number of instances (mostly one)
that are allowed to be made. We also receive a global point of access to it (them).
Structure
Ensure that only one instance of a class is created.
Provide a global point of access to the object.
107. Singleton
Where to use
When only one instance or a specific number of instances of a class are allowed. Facade
objects are often Singletons because only one Facade object is required
Logger Classes
Configuration Classes
Accessing resources in shared mode
108. Singleton
Example
class Singleton
{
private static Singleton m_instance;
private Singleton()
{
...
}
public static synchronized Singleton getInstance()
{
if (m_instance == null)
m_instance = new Singleton();
return m_instance;
}
...
public void doSomething()
{
...
}
}
- The getInstance() method ensure that only one
instance of the class is created.
- The only way f instantiating the class to be
through the getInstance() method.
- The getInstance method is used also to provide
a global point of access to the object and it can
be used like this:
Singleton.getInstance().doSomething();
109. Singleton
Example : Thread-safe implementation for multithreading use
//Lazy instantiation using double locking mechanism.
class Singleton
{
private static Singleton m_instance;
private Singleton()
{
System.out.println("Singleton(): Initializing Instance");
}
public static Singleton getInstance()
{
if (m_instance == null)
{
synchronized(Singleton.class)
{
if (m_instance == null)
{
System.out.println("getInstance(): First time
getInstance was invoked!");
m_instance = new Singleton();
}
}
}
return m_instance;
}
public void doSomething()
{
System.out.println("doSomething(): Singleton does something!");
}
}
//Early instantiation using implementation with static field.
class Singleton
{
private static Singleton m_instance = new Singleton();
private Singleton()
{
System.out.println("Singleton(): Initializing Instance");
}
public static Singleton getInstance()
{
return m_instance;
}
public void doSomething()
{
System.out.println("doSomething(): Singleton does
something!");
}
}
110. Singleton
Example : Multiple instances
Multiple singleton instances if classes loaded by different classloaders access a singleton.
If a class(same name, same package) is loaded by 2 diferent classloaders they represents 2
different clasess in memory.
Serialization
If the Singleton class implements the java.io.Serializable interface, when a singleton is serialized
and then deserialized more than once, there will be multiple instances of Singleton created.
In order to avoid this the readResolve method should be implemented.
public class Singleton implements Serializable {
// This method is called immediately after an object of this class is deserialized.
// This method returns the singleton instance.
protected Object readResolve() {
return getInstance();
}
}
111. Singleton
Why
Controlled access to unique instance.
Reduced name space.
Allows refinement of operations and representations.
Drawbacks/consequences
Singleton pattern is also considered an anti-pattern by some people, who feel that it is overused, introducing unnecessary limitations in situations where a sole instance of a class is not actually required.
The singleton instance is obtained using the class name. At the first view this is an easy way to access it, but it is not very flexible. If we need to replace the Singleton class, all the references in the code should be changed accordingly
112. Builder
Intention is to abstract steps of construction of objects so that different implementations of
these steps can construct different representations of objects.
Structure
Builder
Abstract interface for creating objects (product).
Concrete Builder
Provide implementation for Builder. Construct and
assemble parts to build the objects.
Director
The Director class is responsible for managing the
correct sequence of object creation. It receives a
Concrete Builder as a parameter and executes the
necessary operations on it.
Product
The final object that will be created by the Director
using Builder.
113. Builder
Where to use
When the algorithm for creating a complex object should be independent of the parts that
make up the object and how they are assembled
When the construction process must allow different representations for the object that is
constructed
When you want to insulate clients from the knowledge of the actual creation process and/or
resulting product.
114. Builder
Example
We will see code example for better understanding
For instance to build a house, we will take several steps:
1. Build floor
2. Build walls
3. Build roof
•Let's use an abstract class HouseBuilder to define these three steps.
•Any subclass of HouseBuilder will follow these three steps to build house
•Then we use a HouseDirector class to force the order of these three steps
•The HouseClient orders the building of two houses
• Wood house
• Brick House
•Even though the houses are of different types (wood and brick) they are built the same
way
115. Builder
Why
The built object is shielded from the details of its construction.
Code for construction is isolated from code for representation and both are easy to replace
without affecting the other.
Gives you control over the construction process.
Gives you the possibility to reuse and/or change the process and/or product independently.
Drawbacks/consequences
Need flexibility in creating various complex objects. Need to create complex, aggregate
objects
116. Adapter
The Adapter pattern is used to translate the interface of one class into another interface.
Structure
Client
Expects a certain interface
Target
Interface expected by client
Adaptee
The available interface
Adapter
Bridges the gap between the Target interface and
the available interface Adaptee.
117. Adapter
Where to use
When you want to use an existing class, and its interface does not match the one you need
When you want to create a reusable class that cooperates with unrelated or unforeseen
classes, that is, classes that don't necessarily have compatible interfaces
When you want to increase transparency of classes
When you want to make a pluggable kit
118. Adapter
Example
We will see code example for better understanding
•FileManagerUtil is the existing utility class that we would like
to adapt to FileManager interface
•We will do the actual adaptation in the class FileManagerImpl
• It uses the desired interface and the existing functionality
through inheritance
120. Facade
Provides a unified interface to a set of interfaces in a subsystem.
It defines a higher-level interface that makes the subsystem easier to use.
Structure
Client
The object using the facade to access resources
Facade
Abstracts the internal resources from the rest of the
application
121. Facade
Where to use
When you want to use an existing class, and its interface does not match the one you need
When you want to create a reusable class that cooperates with unrelated or unforeseen
classes, that is, classes that don't necessarily have compatible interfaces
When you want to increase transparency of classes
When you want to make a pluggable kit
122. Facade
Example
The Facade class uses the classes
AccountManager, SecurityManager,
AccountReference and BankAccount to
perform the appropriate actions. By using
the Facade pattern we decouple the client
code from the implementation and
security details when performing tasks
related to the bank account.
124. Facade
Why
Combines very complex method calls and code blocks into a single method that performs a
complex and recurring task
It reduces code dependencies between libraries or packages
Low coupling between the client code and other packages
Reduces network calls
Drawbacks/consequences
Less control of what goes on beyond the surface
If some classes require small variations to the implementation of Facade methods, we might
end up with a mess
125. Proxy
A Proxy is a structural pattern that provides a stand-in for another object in order to control
access to it.
Structure
Subject
Interface implemented by the RealSubject and
representing its services.
RealSubject
The real object that the proxy represents
Proxy
Maintains a reference that allows the Proxy to access the
RealSubject
Implements the same interface implemented by the
RealSubject so that the Proxy can be substituted for the
RealSubject
Controls access to the RealSubject and may be
responsible for its creation and deletion
126. Proxy
Where to use
When the creation of one object is relatively expensive it can be a good idea to replace it
with a proxy that can make sure that instantiation of the expensive object is kept to a
minimum.
Proxy pattern implementation allows for login and authority checking before one reaches
the actual object that's requested
Can provide a local representation for an object in a remote location
128. Proxy
Why
Gives the ability to control access to an object, whether it's because of a costly creation
process of that object or security issues.
Drawbacks/consequences
Introduces another abstraction level for an object, if some objects accesses the target object
directly and another via the proxy there is a chance that they get different behavior this may
or may not be the intention of the creator
129. Chain of Responsibility
The Chain-of-responsibility pattern lets more than one object handle a request without mutual
knowledge.
Structure
Client
Sends commands to the first object in the chain
that may handle the command
Handler
Defines an interface for handling requests
ConcreteHandler(RequestHandler)
- Handles the requests it is responsible for
- If it can handle the request it does so, otherwise
it sends the request to its successor
Places all handlers in a chain which lets the handler objects pass the request along to the next
handler in the chain until one handles it, or the end of the chain is reached.
130. Chain of Responsibility
Where to use
When more than one object may handle a request, and the handler isn't known
When you want to issue a request to one of several objects without specifying the receiver
explicitly
When the set of objects that can handle a request should be specified dynamically
132. Chain of Responsibility
Why
It reduces coupling
It increases the flexibility of handling a request
Drawbacks/consequences
Reception isn't guaranteed since a request has no explicit receiver, there's no guarantee it
will be handled unless the chain is configured properly
133. Command
The Command pattern is used to create objects that represents actions and events in an
application.
Structure
Client
Creates a ConcreteCommand object and sets its receiver
ConcreteCommand
Extends the Command interface, implementing the
Execute method by invoking the corresponding
operations on Receiver. It defines a link between the
Receiver and the action.
Command
Declares an interface for executing an operation
Invoker
Asks the command to carry out the request
Receiver
Knows how to perform the operations
- encapsulate a request in an object
- allows the parameterization of clients with different requests
- allows saving the requests in a queue
134. Command
Where to use
Where you want a action that can be represented in many ways, like dropdown menu,
buttons and popup menu
To create undo/redo functionality
136. Command
Why
A command object is a possible storage for procedure parameters. It can be used while
assembling the parameters for a function call and allows the command to be set aside for
later use
A class is a suitable place to collect code and data related to a specific action or event
It allows the reaction to a command to be executed some time after it has occurred
Command objects enables data structures containing multiple commands
Command objects supports undo-able operations, provided that the command objects are
stored (for example in a linked list).
Drawbacks/consequences
There are implementations of this design pattern in which the invoker is aware of the
concrete commands classes
This is wrong making the implementation more tightly coupled. The invoker should be aware
only about the abstract command class.
137. Mediator
Define an object that encapsulates how a set of objects interact.
Structure
Mediator
Defines an interface for communicating colleague objects.
ConcreteMediator
Knows the colleague classes and keep a reference to the
colleague classes.
- Implements the communication and transfer the
message between the colleague classes
Colleague classes
Keep a reference to its Mediator object
- Communicates with the Mediator whenever it would
have otherwise communicated with another Colleague
With the mediator pattern communication between objects is encapsulated with a mediator
object. Objects no longer communicate directly with each other, but instead communicate
through the mediator.
138. Mediator
Where to use
The Mediator pattern can be used when a set of objects communicate in well-specified but
complex ways and the resulting interdependencies are unstructured and hard to grasp
If it is difficult to reuse an object because it refers to and communicates with many other
objects this pattern is a good solution
A behavior that is distributed between several classes should be customizable without a lot
of subclassing
140. Mediator
Why
Limited subclassing, since a mediator localizes behavior that otherwise would be distributed
among several objects. Changing some behavior requires us to subclass only the mediator.
Colleagues become decoupled which allows us to vary and reuse colleague and mediator
classes independently
A mediator simplifies object protocols since it replaces many-to-many interactions with one-
to-many interactions between the mediator and its colleagues. One-to-many interactions
are easier to understand, maintain, and extend
The mediator abstracts object cooperation. The mediator lets you focus on how objects
interact apart from their individual behaviors which can help clarify how objects interact in a
system
Drawbacks/consequences
The Mediator pattern can have a performance impact on a system. Since all communication
must go through the mediator, it can become a bottleneck
In practice mediators tends to become more complex and complex. A good practice is to
take care to make the mediator classes responsible only for the communication part
141. Observer
Define a one-to-many dependency between objects so that when one object changes state, all its
dependents are notified and updated automatically.
Structure
Subject
Interface or abstract class defining the operations for
attaching and detaching observers to the client.
Observer (IObserver)
Interface or abstract class defining the operations to be
used to notify this object.
Observer class
It maintains the state of the object and when change in
the state occurs it notifies the attached observers
Pattern that enables publish/subscribe functionality. This is accomplished by an autonomous
object, publisher that allows other objects to attach or detach their subscription as they like.
The pattern does not impose any limit to the number of observers that can attach, or
subscribe, themselves for notification on future changes in the publisher's state.
142. Observer
Where to use
When an object wants to publish information and many objects will need to receive that
information
The change of a state in one object must be reflected in another object without keeping the
objects tightly coupled
The framework needs to be enhanced in future with new observers with minimal changes
144. Observer
Why
Makes for a loose coupling between publisher and subscriber as the publisher does not need
to know who or how many subscribers there will be
Drawbacks/consequences
In a complex scenario there may be problems to determining whether the update to the
publisher is of relevance to all subscribers or just some of them. Sending an update signal to
all subscribers might impose a communication overhead of not needed information
145. Reference
Design Principles and Design Patterns – Robert C. Martin
www.objectmentor.com
Applying UML and Patterns 3rd
Edition – Craig Larman
http://www.oodesign.com/
The Gang of Four (GoF) Patterns
There are four primary symptoms that tell us that our designs are rotting. They are not
orthogonal, but are related to each other in ways that will become obvious. they are:
rigidity, fragility, immobility, and viscosity.
Rigidity - It is hard to change because every change affects too many other parts of the system
Fragility - When you make a change, unexpected parts of the system break
Immobility - It is hard to reuse in another application because it cannot be disentangled from the current application
Viscosity - Viscosity comes in two forms:
viscosity of the design - When faced with a change, engineers usually find more than one way to make the change. Some of the ways preserve the design, others do not (i.e. they are hacks.) When the design preserving methods are harder to employ than the hacks, then the viscosity of the design is high. It is easy to do the wrong thing, but hard to do the right thing.
viscosity of the environment. Viscosity of environment comes about when the development environment is slow and inefficient. For example, if compile times are very long, engineers will be tempted to make changes that don’t force large recompiles, even though those changes are not optiimal from a design point of view. If the source code control system requires hours to check in just a few files, then engineers will be tempted to make changes that require as few check-ins as possible, regardless of whether the design is preserved. These four symptoms are the tell-tale signs of poor architecture.
The immediate cause of the degradation of the design is well understood. The requirements have been changing in ways that the initial design did not anticipate. Often
these changes need to be made quickly, and may be made by engineers who are not familiar with the original design philosophy. So, though the change to the design works, it somehow violates the original design. Bit by bit, as the changes continue to pour in, these violations accumulate until malignancy sets in. However, we cannot blame the drifting of the requirements for the degradation of the design. We, as software engineers, know full well that requirements change. Indeed, most of us realize that the requirements document is the most volatile document in the project. If our designs are failing due to the constant rain of changing requirements, it is our designs that are at fault. We must somehow find a way to make our designs resilient to such changes and protect them from rotting.
What kind of changes cause designs to rot? Changes that introduce new and
unplanned for dependencies. Each of the four symptoms mentioned above is either
directly, or indirectly caused by improper dependencies between the modules of the
software. It is the dependency architecture that is degrading, and with it the ability of
the software to be maintained. In order to forestall the degradation of the dependency architecture, the dependencies between modules in an application must be managed. This management consists of the creation of dependency firewalls. Accross such firewalls, dependencies do not propogate. Object Oriented Design is replete with principles and techniques for building such firewalls, and for managing module dependencies. It is these principles and techniques that will be discussed in the remainder of this chapter. First we will examine the principles, and then the techniques, or design patterns, that help maintain the dependency architecture of an application.
The major benefits received from the open-closed principle are modules that are open for extension, yet closed for modification. Why are these benefits so big? They are big because they seek to achieve two goals of object-oriented programming. With the module being open for extension, it is highly reusable and can be used to satisfy a ever changing list of requirements. Also, the module is extremely maintainable, as it never needs to change.
Further, the Liskov Substitution Principle states that by inheriting you shouldn’t weaken the post conditions nor should you strengthen the pre conditions and you also shouldn’t change expected behavior.
Let's assume that the Rectangle object is used somewhere in the application. We extend the application and add the Square class. The square class is returned by a factory pattern, based on some conditions and we don't know the exact what type of object will be returned. But we know it's a Rectangle. We get the rectangle object, set the width to 5 and height to 10 and get the area. For a rectangle with width 5 and height 10 the area should be 50. Instead the result will be 100
With this hierarchy, what may surprise you is that we have not changed the implementation of the closeAccount() method in any of the classes. The pre-conditions and the post-conditions remain the same. But in essence, what has happened is that the user will not make any assumption about the behaviour of the account object he is dealing with. This makes the module more maintainable and reusable in the sense that now it is very easy to add another type of account which may impose some other pre-condition and post-condition without breaking the LSP and Design by Contract.
ConclusionIt may seem from the above discussion that overriding is the main problem with LSP and in that case inheritance makes no sense. To some extent, it is puzzling but always keep the Design by Contract principle in mind before you override. If you are unable to comply with the same, then it might be worth revisiting your class diagrams. Always make sure that the derived class must enforce less strict pre-conditions while overriding any base class method. Try to think about the situation on your own and surely you will come up with some logic why LSP is so important for a good OO design.
Many client specific interfaces are better than one general purpose interface
Create an interface per client type not per client
Avoid needless coupling to clients
There's another aspect that needs be to considered. What happens if the data source is read-only? The methods for inserting and updating data are not needed. On the other hand, if the DAO object should implement the DAO interface, it will have to provide a null implementation for those methods defined in the interface. This is still acceptable, but the design is gradually going wrong. What if there is a need to rotate the file data source to a different file once a certain amount of data has been written to the file? That will require a separate method to add to the DAO interface. This is just to add the flexibility to the clients using this FileDAO object to enable them to choose either the normal append feature to the file data source or to make use of the improved file rotation feature.
Like every principle Interface Segregation Principle is one principle which require additional time and effort spent to apply it during the design time and increase the complexity of code. But it produce a flexible design. If we are going to apply it more than is necessary it will result a code containing a lot of interfaces with single methods, so applying should be done based on experience and common sense in identifying the areas where extension of code are more likely to happens in the future.
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
The DataWriter class uses the DataCollector class.
The DataCollector class is responsible for collecting the data from some data source and passing the required object to the DataWriter class.
The DataWriter class in turn accepts the passed object and uses another class DatabaseWriter to write data to the database.
it is tied to the implementation of the DatabaseWriter object
When this principle is applied it means that the high level classes are not working directly with low level classes, they are using interfaces as an abstract layer. In that case the creation of new low level objects inside the high level classes(if necessary) can not be done using the operator new. Instead, some of the Creational design patterns can be used, such as Factory Method, Abstract Factory, Prototype.
The Template Design Pattern is an example where the DIP principle is applied.
Of course, using this principle implies an increased effort and a more complex code, but more flexible. This principle can not be applied for every class or every module. If we have a class functionality that is more likely to remain unchanged in the future there is not need to apply this principle.
For example, suppose an Employee class has a method for computing the employee's annual bonus:
class Employee { Money computeBonus() { /* skimpy default bonus */ } // etc.}
Different subclasses of Employee: Manager, Programmer, Secretary, etc. may want to override this method to reflect the fact that some types of employees (managers) get more generous bonuses than others (secretaries and programmers):
class Manager extends Employee { Money computeBonus() { /* gerenous bonus */ } // etc.}
There are several problems with this solution.
1. All programmers get the same bonus. What if we wanted to vary the bonus computation among programmers? Would we need to introduce a special subclass of Programmer?
class SeniorProgrammer extends Programmer { Money computeBonus() { /* gerenous bonus */ } // etc.}
Note also that this leads to code duplication.
2. What if we wanted to change the bonus computation for a particular employee? For example, what if we wanted to promote Smith from programmer to senior programmer? Would this require us to recompile any code?
3. What if we decided to give all programmers the same generous bonus that managers get? What changes would we need to make? Should "generous bonus" become the new default algorithm that is overridden in the Secretary class with the skimpy bonus algorithm? Should we copy and paste the "generous bonus" algorithm from manager to Programmer?
Alternatively, we can use the Strategy pattern and introduce a separate hierarchy of bonus calculators:
It all started in civil engineering and architecture. In the seventies,
architecture was considered as a discipline that required a lot of
experience. But over a period of time, people like Christopher
Alexander surprised the community by publishing books on
architecture, there by they made it possible for people who are even
without specialized knowledge and experience to give architectural
solutions.
The idea was simple, he identified the similarities between architectures
that proved to be good, and identified the principles and wrote them as
solutions to common design problems. These were named as
PATTERNS in architecture.
The simplest patterns may be summed up in no more than a sentence
or two.
For ex: Using a database to store information for a website is a pattern.
A complex one perhaps require more explanation.
Note: UML is widely used to describe patterns
In fact any developer who as build anything with J2EE, or even with
significant components of J2EE has probably discovered at least one
ore two of the patterns already.
Design Patterns are recurring solutions to recurring problems.
Patterns are gathered through experience and are based on proven
solutions. A pattern becomes a pattern only after it has been verified
several times in real world systems. Hence patterns gives us the
following advantages.
1. It promotes reuse.
2. It prevent us from reinventing the wheel
3. It improves our productivity by making us work faster
and efficiently.
4. Patterns also give us vocabulary, which improves
communication between architects and designers.
5. Patterns encourage us to combine them to solve larger
problems.
Note: Finding patterns is a matter of experience and thought process
and not novelty.
Design Patterns are recurring solutions to recurring problems.
Patterns are gathered through experience and are based on proven
solutions. A pattern becomes a pattern only after it has been verified
several times in real world systems. Hence patterns gives us the
following advantages.
1. It promotes reuse.
2. It prevent us from reinventing the wheel
3. It improves our productivity by making us work faster
and efficiently.
4. Patterns also give us vocabulary, which improves
communication between architects and designers.
5. Patterns encourage us to combine them to solve larger
problems.
Note: Finding patterns is a matter of experience and thought process
and not novelty.
We identify patterns from experience. Every experienced architect
or designer has figured out that in all the majority of projects, similar
problems occur and most interestingly, solutions to these problems
are also similar. This does not mean that the actual solution will be
exactly the same. However, it does mean that all solutions share
basic concepts. When looked at from a point of abstraction, we
could say that all these solutions and problems represent a common
abstract problem with a common abstract solution.
However, a set of solutions becomes a pattern only after they have
been verified. Of-course verifying complex patterns in software
engineering might be a little more difficult than verifying simpler
architectural patterns. So don’t identify patterns directly, first
identify pattern candidates. Pattern candidates should be
standalone solutions with as few connections to the outer world as
possible. We have to validate the pattern candidates. The thumb
rule in validating the pattern is
1. The pattern should be proved in at least three different
systems.
Basically which means that the pattern should be verified thoroughly
as possible.
Pls Note: A pattern that cannot fulfill the goals can do more
damage, and can bring bad reputation to patterns.
Before using a pattern, understand it completely. This requires that we
study the solutions section, problem section, and the example section
etc. Then we should understand all the components , classes,
interfaces and objects that take part in the pattern and their
relationships. We should check once again that whether we have
selected the appropriate pattern.
Note: Learning many patterns is not sufficient for becoming a good
designer. We have to understand every pattern we learn and we
should be clear on when to use which pattern.
Antipatterns describe negative solutions, which cause more
problems than they address. Antipatterns describes design
solutions that do not work in practice due to unintended and
unforeseen negative consequences.
For example, a typical wrong decision made in the first J2EE
applications was to model entity beans with a fine grained interfaces
and accessing them directly. This added a considerable remote
method invocation and transaction management overhead, which
resulted in poorly performing and unscalable application.
There are different types of patterns that we will look at. The majority of them are design patterns that help us structure our components and code in order to solve specific problems. However, before looking at some of the design patterns, we will look at a different type of pattern. Some might call them process patterns. They describe an appropriate way of performing tasks.
We will look at the GRASP patterns described by Craig Larman in his book: Applying UML and Patterns, 3ed. GRASP stands for General Responsibility Assignment Software Patterns.
There are several GRASP patterns, but we will only look at a few of the more important ones. Some of them are simply good design principles, and one can argue whether they are really patterns. For example, High Cohesion and Low Coupling are two that are well known design principles and not really patterns.
Expert
Which class, in the general case is responsible?
.
You want to assign a responsibility to a class
You want to assign the responsibility to a class that is already present in your design if possible
A class already has access to the information required to carry out the responsibility
You want to avoid or minimize additional dependencies
In the point -of -sale application, who should be responsible
for authorising different kinds of payments?
– Note: Payments may be in
• cash (authorising involves determining if it is
counterfeit)
• credit (authorising involves communication with bank)
• check (authorising involves driver license record)
Assume that :
A point-of-sale terminal application needs to manipulate a modem in order to transmit credit payment request
The operating system provides a low-level function call API for doing so.
A class called CreditAuthorizationService is responsible for talking to the modem
If CreditAuthorizationService invokes the low –level API function calls directly, it is highly coupled to the API of the particular operating system. If the class needs to be ported to another operating system, then it will requiure modification.
Add an intermediate Modem class between the CreditAuthorizationService and the modem API. It is responsible for translating abstract modem requests to the API and creating an Indirection between the CreditAuthorizationService and the modem.
Assume that :
A point-of-sale terminal application needs to manipulate a modem in order to transmit credit payment request
The operating system provides a low-level function call API for doing so.
A class called CreditAuthorizationService is responsible for talking to the modem
If CreditAuthorizationService invokes the low –level API function calls directly, it is highly coupled to the API of the particular operating system. If the class needs to be ported to another operating system, then it will requiure modification.
Add an intermediate Modem class between the CreditAuthorizationService and the modem API. It is responsible for translating abstract modem requests to the API and creating an Indirection between the CreditAuthorizationService and the modem.
Builder Pattern
Motivation
The more complex an application is the complexity of classes and objects used increases. Complex objects are made of parts produced by other objects that need special care when being built. An application might need a mechanism for building complex objects that is independent from the ones that make up the object. If this is the problem you are being confronted with, you might want to try using the Builder (or Adaptive Builder) design pattern.
This pattern allows a client object to construct a complex object by specifying only its type and content, being shielded from the details related to the object’s representation. This way the construction process can be used to create different representations. The logic of this process is isolated form the actual steps used in creating the complex object, so the process can be used again to create a different object form the same set of simple objects as the first one.Intent
Defines an instance for creating an object but letting subclasses decide which class to instantiate
Refers to the newly created object through a common interface
Implementation
The Builder design pattern uses the Factory Builder pattern to decide which concrete class to initiate in order to build the desired type of object, as we will see below in the UML diagram: The participants classes in this pattern are:
The Builder class specifies an abstract interface for creating parts of a Product object.
The ConcreteBuilder constructs and puts together parts of the product by implementing the Builder interface. It defines and keeps track of the representation it creates and provides an interface for saving the product.
The Director class constructs the complex object using the Builder interface.
The Product represents the complex object that is being built.
The client, that may be either another object or the actual client that calls the main() method of the application, initiates the Builder and Director class. The Builder represents the complex object that needs to be built in terms of simpler objects and types. The constructor in the Director class receives a Builder object as a parameter from the Client and is responsible for calling the appropriate methods of the Builder class. In order to provide the Client with an interface for all concrete Builders, the Builder class should be an abstract one. This way you can add new types of complex objects by only defining the structure and reusing the logic for the actual construction process. The Client is the only one that needs to know about the new types, the Director needing to know which methods of the Builder to call.The following example discusses the case of a text converting application:
The Client needs to convert a document from RTF format to ASCII format. There for, it calls the method createASCIIText that takes as a parameter the document that will be converted. This method calls the concrete builder, ASCIIConverter, that extends the Builder, TextConverter, and overrides its two methods for converting characters and paragraphs, and also the Director, RTFReader, that parses the document and calls the builder’s methods depending on the type of token encountered. The product, the ASCIIText, is built step by step, by appending converted characters.
//Abstract Builder class abstract class TextConverter{ abstract void convertCharacter(char c); abstract void convertParagraph(); } // Product class ASCIIText{ public void append(char c){ //Implement the code here } } //Concrete Builder class ASCIIConverter extends TextConverter{ ASCIIText asciiTextObj;//resulting product /*converts a character to target representation and appends to the resulting*/ object void convertCharacter(char c){ char asciiChar = new Character(c).charValue(); //gets the ascii character asciiTextObj.append(asciiChar); } void convertParagraph(){} ASCIIText getResult(){ return asciiTextObj; } } //This class abstracts the document object class Document{ static int value; char token; public char getNextToken(){ //Get the next token return token; } } //Director class RTFReader{ private static final char EOF='0'; //Delimitor for End of File final char CHAR='c'; final char PARA='p'; char t; TextConverter builder; RTFReader(TextConverter obj){ builder=obj; } void parseRTF(Document doc){ while ((t=doc.getNextToken())!= EOF){ switch (t){ case CHAR: builder.convertCharacter(t); case PARA: builder.convertParagraph(); } } } } //Client public class Client{ void createASCIIText(Document doc){ ASCIIConverter asciiBuilder = new ASCIIConverter(); RTFReader rtfReader = new RTFReader(asciiBuilder); rtfReader.parseRTF(doc); ASCIIText asciiText = asciiBuilder.getResult(); } public static void main(String args[]){ Client client=new Client(); Document doc=new Document(); client.createASCIIText(doc); system.out.println("This is an example of Builder Pattern"); } }
Applicability & Examples
Builder Pattern is used when:
the creation algorithm of a complex object is independent from the parts that actually compose the object
the system needs to allow different representations for the objects that are being built
Example 1 - Vehicle Manufacturer.
Let us take the case of a vehicle manufacturer that, from a set of parts, can build a car, a bicycle, a motorcycle or a scooter. In this case the Builder will become the VehicleBuilder. It specifies the interface for building any of the vehicles in the list above, using the same set of parts and a different set of rules for every type of type of vehicle. The ConcreteBuilders will be the builders attached to each of the objects that are being under construction. The Product is of course the vehicle that is being constructed and the Director is the manufacturer and its shop.
Example 1 - Students Exams.
If we have an application that can be used by the students of a University to provide them with the list of their grades for their exams, this application needs to run in different ways depending on the user that is using it, user that has to log in. This means that, for example, the admin needs to have some buttons enabled, buttons that needs to be disabled for the student, the common user. The Builder provides the interface for building form depending on the login information. The ConcreteBuilders are the specific forms for each type of user. The Product is the final form that the application will use in the given case and the Director is the application that, based on the login information, needs a specific form.
Specific problems and implementation
Builder and Abstract Factory
The Builder design pattern is very similar, at some extent, to the Abstract Factory pattern. That’s why it is important to be able to make the difference between the situations when one or the other is used. In the case of the Abstract Factory, the client uses the factory’s methods to create its own objects. In the Builder’s case, the Builder class is instructed on how to create the object and then it is asked for it, but the way that the class is put together is up to the Builder class, this detail making the difference between the two patterns.
Common interface for products
In practice the products created by the concrete builders have a structure significantly different, so if there is not a reason to derive different products a common parent class. This also distinguishes the Builder pattern from the Abstract Factory pattern which creates objects derived from a common type.
Consider the graphics above, where the Client classes makes calls to the
BankAccountFacade class. The Facade class uses the classes AccountManager,
SecurityManager, AccountReference and BankAccount to perform the
appropriate actions. By using the Facade pattern we decouple the client
code from the implementation and security details when performing tasks
related to the bank account.