How Design Patterns Solve
Design Problems
1
How Design Patterns Solve Design Problems
1. Finding Appropriate Objects
2. Determining Object Granularity
3. Specifying Object Interfaces
4. Specifying Object Implementations
5. Putting Reuse Mechanisms to Work
6. Designing for Change
2
Finding Appropriate Objects
Design patterns help you identify less-obvious abstractions and the objects that can capture them.
● Examples:
○ Strategy: describes how to implement interchangeable families of algorithms.
○ State: represents each state of an entity as an object.
● These objects are seldom found during analysis or even the early stages of design; they're
discovered later in the course of making a design more flexible and reusable.
3
Strategy State
4
Determining Object Granularity
Design patterns help to decide what should be an object?
● Facade: how to represent complete subsystems as objects
● Flyweight: how to support huge numbers of objects at the finest granularities.
● Specific ways of decomposing an object into smaller objects.
○ Abstract Factory and Builder yield objects whose only responsibilities are creating other objects.
○ Visitor and Command yield objects whose only responsibilities are to implement a request on another object
or group of objects
5
Facade Flyweight
6
Specifying Object Interfaces
Design patterns help you define interfaces by identifying their key elements and the kinds of data that get
sent across an interface.
A design pattern might also tell you what not to put in the interface. ’
Example:
● Memento pattern describes how to encapsulate and save the internal state of an object so that the
object can be restored to that state later.
● Memento objects must define two interfaces: a restricted one that lets clients hold and copy
mementos, and a privileged one that only the original object can use to store and retrieve state in
the memento.
7
Memento
8
Specifying Object Interfaces
Design patterns also specify relationships between interfaces
● Some classes require to have similar interfaces, or place constraints on the interfaces of some
classes.
Examples:
● Decorator and and Proxy patterns require the interfaces of Decorator and Proxy objects to be
identical to the decorated and proxied objects.
● Visitor pattern require Visitor interface to reflect all classes of objects that visitors can visit.
9
Decorator Proxy
10
Specifying Object Implementations
An object's class defines how the object is implemented and type refers to its interface.
Class inheritance versus Interface Inheritance
Class inheritance defines an object's implementation in terms of another object's implementation. It's a
mechanism for code and representation sharing.
Interface inheritance (or subtyping) describes when an object can be used in place of another
Many of the design patterns depend on this distinction. Examples:
● Chain of Responsibility must have a common type, but usually they don't share a common
implementation. → Interface inheritance
● Composite: Component defines a common interface, but Composite often defines a common
implementation. → Class inheritance
● Command, Observer, State, and Strategy are often implemented with abstract classes that are pure
interfaces. → Interface inheritance
11
Chain of Responsibility Composite
12
Specifying Object Implementations
Programming to an Interface, not an Implementation
Inheritance enables reuse implementation and polymorphism.
When using a class that inherit an abstract class, the client only knows about the abstract class and its
interface; NOT the specific types of objects they use or the classes that implement these objects.
Reduces implementation dependencies between subsystems and lead to the principle of reusable oo design:
‘Program to and interface, not an implementation’
Creational patterns ensure that your system is written in terms of interfaces, not implementations. By
abstracting the process of object creation, these patterns give you different ways to associate an interface
with its implementation transparently at instantiation.
Examples: Abstract Factory, Builder, Factory Method, Prototype and Singleton let you avoid instantiate
concrete classes somewhere in your system
13
Putting Reuse Mechanisms to Work
Class inheritance vs object composition
Class inheritance : white box reuse Object composition: black-box reuse
● Supported by programming languages, ● Defined dynamically at run-time, objects
defined statically at compile-time, are accessed solely through their
straightforward to use and easier to modify interfaces, object can be replaced at run-
implementation being reused. time by another object of the same type,
● Cannot change the implementations fewer implementation dependencies, small
inherited from parent classes at run-time class hierarchies
● Implementation dependency between a ● more objects (if fewer classes) and the
subclass and its parent class (inheritance system's behavior will depend on their
can breaks encapsulation) interrelationships
Designs are often made more reusable (and simpler) by depending more on object composition
14
Putting Reuse Mechanisms to Work
Delegation vs inheritance
● With inheritance, an inherited operation can always refer to the receiving object through the this
member variable
● With delegation, the receiver passes itself to the delegate to let the delegated operation refer to
the receiver
Delegation is a way of making composition as powerful for reuse as inheritance.
● Makes it easy to compose behaviors at run-time and to change the way they're composed.
● Dynamic, highly parameterized software is harder to understand than more static software. There
are also run-time inefficiencies
Delegation is a good design choice only when it simplifies more than it complicates.
15
Putting Reuse Mechanisms to Work
State: an object delegates requests to a State object that represents its current state.
Strategy:an object delegates a specific request to an object that represents a strategy for carrying out the
request.
● An object will only have one state, but it can have many strategies for different requests.
● The purpose of both patterns is to change the behavior of an object by changing the objects to which it delegates
requests.
Visitor: the operation that gets performed on each element of an object structure is always delegated to the
Visitor object.
Other patterns use delegation less heavily:
● Mediator introduces an object to mediate communication between other objects. .
● Chain of Responsibility handles requests by forwarding them from one object to another along a chain of objects.
● Bridge decouples an abstraction from its implementation. If the abstraction and a particular implementation are
closely matched, then the abstraction may simply delegate operations to that implementation
16
Visitor
17
Putting Reuse Mechanisms to Work
Inheritance versus Parameterized Types
Parameterized types, also known as generics and templates
● A technique that lets you define a type without specifying all the other types it uses.
● The unspecified types are supplied as parameters at the point of use.
Give us a third way (in addition to class inheritance and object composition) to compose behavior in
object-oriented systems
Example: To parameterize a sorting routine by the operation it uses to compare elements, we could make
the comparison.
1. Inheritance: An operation implemented by subclasses (Template)
2. Composition: The responsibility of an object that's passed to the sorting routine (Strategy)
3. Parameterized type: An argument of generic that specifies the name of the function to call to
compare the elements.
18
Putting Reuse Mechanisms to Work
Relating Run-Time and Compile-Time Structures
● The two structures are largely independent.
○ The code structure is frozen at compile-time; it consists of classes in fixed inheritance relationships.
○ A program's run-time structure consists of rapidly changing networks of communicating objects
Many design patterns (in particular those that have object scope) capture the distinction between
compile-time and run-time structures explicitly.
● Composite and Decorator are especially useful for building complex run-time structures.
● Observer involves run-time structures that are often hard to understand unless you know the
pattern.
● Chain of Responsibility also results in communication patterns that inheritance doesn't reveal.
19
Observer
20
Designing for Change
Some common causes of redesign and the design patterns that address them:
● Creating an object by specifying a class explicit
○ Abstract Factory, Factory, Prototype
● Dependence on specific operations -
○ Command and Chain of Responsibility
● Dependence on hardware and software platform
○ Abstract Factory, Bridge
● Dependence on object representations or implementations
○ Abstract Factory, Bridge, Memento, Proxy
● Algorithmic dependencies
○ Builder, Iterator, Strategy, Template, Method and Visitor
● Tight coupling
○ Abstract Factory, Bridge, Chain of Responsibility, Command, Facade, Mediator, Observer
● Extending functionality by subclassing.
○ Bridge, Chain of Responsibility, Composite, Decorator, Observer, Strategy
● Inability to alter classes conveniently
○ Adapter, Decorator, Visitor
21
Designing for Change
Design patterns play an important role in the development of three broad classes of software:
● Application Programs :
○ Internal reuse, maintainability, and extension are high priorities.
● Toolkits (class/component libraries) :
○ code reuse
● Frameworks :
○ Frameworks emphasize design reuse over code reuse.
○ Design patterns are more abstract than frameworks.
○ Design patterns are smaller architectural elements than frameworks.
○ Design patterns are less specialized than frameworks.
22
How to Select a Design Pattern
23
How to Select a Design Pattern
1. Consider how design patterns solve design problems.
2. Scan Intent sections.
3. Study how patterns interrelate.
4. Study patterns of like purpose.
creational, structural, behavioral
5. Examine a cause of redesign.
find the patterns that help you avoid the causes of redesign
6. Consider what should be variable in your design.
consider what you want to be able to change without redesign
24
Summary
25