5. Design Patterns

advertisement
5. Design Patterns
• Are the answer to a question that commonly
arises “How can I … ?”
• Patterns record successful solutions in software
development for sharing between projects.
• Gang of Four (GoF) Gamma, Helm, Johnson,
Vlissides, - founders of movement.
• Gamma et al, Design Patterns: Elements of
Reusable Object-Oriented Software, Addison
Wesley, 1995.
Patterns solve software structural problems
like:
• Abstraction,
• Encapsulation
• Information hiding
• Separation of concerns
• Coupling and cohesion
• Separation of interface and implementation
• Single point of reference
• Divide and conquer
Patterns also solve non-functional problems
like:
• Changeability
• Interoperability
• Efficiency
• Reliability
• Testability
• Reusability
5.1. Types of Pattern
There are 3 types of pattern …
– Creational: address problems of creating an
object in a flexible way. Separate creation, from
operation/use.
– Structural: address problems of using O-O
constructs like inheritance to organize classes
and objects
– Behavioral: address problems of assigning
responsibilities to classes. Suggest both static
relationships and patterns of communication
(use cases)
5.2. Patterns, Architectures &
Frameworks
• There can be confusion between patterns,
architectures and frameworks.
• Let’s try to distinguish them:
• Architectures model software structure at
the highest possible level, and give the
overall system view. An architecture can use
many different patterns in different
components
• Patterns are more like small-scale or local
architectures for architectural components
or sub-components
• Frameworks are partially completed
software systems that may be targeted at a
particular type of application. These are
tailored by completing the unfinished
components.
Summary of Differences
• Patterns are more general and abstract than
frameworks. A pattern is a description of a
solution, not a solution itself.
• A pattern cannot be directly implemented.
An implementation is an example of a
pattern.
• Patterns are more primitive than
frameworks. A framework can employ
several patterns.
5.3 Catalogues & Languages
• Patterns are grouped into catalogues and
languages
• A catalogue is group of patterns that may
be reasonable to use together
• A language is a more closely related
collection useful for a common problem
domain, e.g. Banking.
5.4 Pattern Templates
• Different authors use different templates to
describe their patterns
• Information is not always presented in the
same way.
• Consult your manual/source !!!
• A typical template would be …
• Name: meaningful text that reflects the problem,
e.g. Bridge, Mediator, Flyweight
• Problem addressed: intent of the pattern,
objectives achieved within certain constraints
• Context: circumstances under which it can occur,
used to determine applicability
• Forces: constraints or issues that solution must
address, forces may conflict!
• Solution: the static and dynamic relationships
among the pattern components. Structure,
participants, collaboration. Solution must resolve
all forces!
5.5. Pattern: Singleton
(Creational)
Name: Singleton
Problem:
How can we guarantee that one and only one
instance of a class can be created?
Context: In some applications it is important
to have exactly one instance of a class, e.g. sales of
one company.
Forces: Can make an object globally accessible as a
global variable, but this violates encapsulation.
Could use class (static) operations and attributes, but
polymorphic redefinition is not always possible.
Solution:
Create a class with a class operation getInstance().
When class is first accessed, this creates relevant
object instance and returns object identity to client.
On subsequent calls of getInstance(), no new
instance is created, but identity of existing object is
returned.
Singleton Structure
Singleton
-uniqueInstance
-singletonData
+getInstance( )
+getSingletonData( )
+singletonOperation( )
-Singleton( )
Object identifier for singleton
instance, class scope or static
Returns object identifier for
unique instance, class-scope
or static
Private constructor only accessible
via getInstance()
getInstance( ) {
if ( uniqueInstance == null )
{ uniqueInstance = new Singleton( ) }
return uniqueInstance
}
Example: Code
Class Singleton {
private static Singleton uniqueInstance = null;
private Singleton( ) { .. } // private constructor
public static Singleton getInstance( ) {
if (uniqueInstance == null)
uniqueInstance = new Singleton();
// call constructor
return uniqueInstance;
}
}
Comments
• To specify a class has only one instance, we make
it inherit from Singleton.
+ controlled access to single object instance through
Singleton encapsulation
+ Can tailor for any finite number of instances
+ namespace not extended by global variables
- access requires additional message passing
- Pattern limits flexibility, significant redesign if
singleton class later gets many instances
5.6. Pattern: Façade
(Structural)
Name: Façade
Problem:
How can we access a large number of classes
with a complex internal interaction in a simple
but safe way?
Solution: Introduce a dedicated interface class
that simplifies the view of the class collection.
Facade Structure
Facade
subsystem classes
<<façade>>
SecurityManager
Pattern Name
+addAccessRight()
+addActor()
+addActorRole()
+removeActor()
AccessRight
+addAccessRight()
Actor
+addActor()
+removeActor()
+changeSalary()
ActorRole
+addActorRole()
Method not in Facade
Comments
• Clients communicate with the subsystem by
sending requests to Façade which forwards
them to the appropriate subsystem object(s).
• Although subsystem objects perform actual
work, Façade may have to translate its
interface to subsystem interfaces.
• Clients that use the Façade don’t have to
access its subsystem objects directly.
• Usually only one Façade object is
required. Thus a Façade object is often a
singleton.
• Factory pattern can be used with Façade
to provide an interface for creating
subsystem objects in a subsystem
independent way.
• Factory can also be used as an alternative
to Façade to hide platform-specific classes.
• Mediator pattern is similar to Façade in
abstracting functionality of classes.
5.7. Pattern: Mediator
(Behavioral)
Problem:
How can we deal with two or more classes
which sometimes interact, but can also be used
separately?
Solution: Mediator promotes loose coupling
by keeping objects from referring to one another
explicitly. Put each interaction between objects
in a separate (Mediator) class. This class
should have references to the objects.
• A pattern for two objects which exist
independently but have some coupling. This
coupling is placed in its own class.
• Used by e.g. ActionListener in graphics
which couples together two graphical
objects, e.g. window & button
Mediator Structure
1
mediator
Mediator
Colleague
*
ConcreteMediator
Concrete
Colleague1
Concrete
Colleague2
*
• Colleagues send and receive requests from a
Mediator object. The mediator implements
the cooperative behavior by routing requests
between appropriate colleagues.
Example: Top-Down Design
1
mediator
Mediator
File_Selector
Colleague
*
Browser
Button
*
My_Application
Text_Field
*
Comments
• Façade, unlike Mediator, abstracts a
subsystem of objects to provide a
convenient interface. Unidirectional.
Façade objects make requests of the
subsystem, but not vice-versa.
• Mediator enables cooperative behaviour,
that colleagues don’t or can’t provide.
Multidirectional.
• Observer pattern and Mediator both
receive notification of changes.
• Observer does so through an abstract
mechanism. Allows source of notification to
be independent of its observers.
• In Mediator, the source must know its
mediator. This makes it possible for
mediator to define reactions to each
stimulus.
5.8. Pattern: Observer
(Behavioral)
Name: Observer
Problem: Define a one-to-many dependency
among objects so that when one object
changes state, all of its dependents are
notified and updated automatically.
Solution: MVC, but refined by separating
abstract from concrete subjects and observers
*
Subject
Update()
attach(Observer)
detach(Observer)
notify()
ConcreteSubject
subjectState()
getState()
setState()
Observer
for all o in
observers {
o.update( ) }
ConcreteObserver
observerState
update()
*
return
subjectState
observerState =
subject.getState( )
• ConcreteSubject notifies its observers
whenever a change occurs that could make
its observers state inconsistent with its own
• After being informed of change, a
ConcreteObserver queries the subject to
reconcile its state with subjects.
• Observer object that initiates change
request postpones its update until it gets
notification from subject. Notify() is not
always called by subject. Can be called by
an observer, or any other object.
• Pattern is well known, has wide range of
variants
aConcrete
Subject:
aConcrete
Subject:
aConcrete
Subject:
setState( )
notify( )
update( )
getState( )
update( )
getState( )
5.9. Pattern: Mock Object
• A pattern where coupling an objects
coupling to another complex object is
replaced by coupling to a simplified proxy.
• C.f. dummy methods in whishful thinking
• Coupling between objects could well be an
interface. Then the mock and real objects
implement this interface.
• Used e.g. in testing objects. (see Section 8)
5.10 Pattern: Factory
Name: (Abstract) Factory
Problem: Provide an interface for creating
families of related or dependent objects
without specifying their concrete classes.
• Control instantiation
• Singleton is a special case of Factory where
only one object can be created.
Factory Structure
AbstractFactory
AbstractProduct
ConcreteProduct1
FactoryMethod()
AnOperation()
Product =
FactoryMethod()
ConcreteFactory
FactoryMethod()
return new
ConcreteProduct()
• Normally, a single instance of a
ConcreteFactory class is created at
runtime.
• This creates product objects having a
particular implementation.
• To create different product objects, clients
should use a different concrete factory.
• AbstractFactory defers creation of product
objects to its ConcreteFactory subclasses.
Factory Class Model
Client
RequiredClass
create objects
MyClass
createObjectOfRequiredClass():RequiredClass
Factory design pattern
5.10.1 Factory Example
• E.g. create objects of different types
• We can order a Car and get an
Aston Martin, MG, Jaguar etc
• We don’t know which factory builds the car,
just that they implement CarFactory.
Owner has created the actual factory
instance.
// we have a reference to owner
CarFactory aFactory = owner.makefactory();
Car myCar =aFactory.makeCar(“AstonMartin”);
class BritishFactory implements CarFactory{
public Car makeCar(String b) throws
Exception {
if(b.equals(“AstonMartin”)) return new
AstonMartin();
else if (..) return ..;
else throw new Exception(b + “doesn’t
exist”);
}
}
Class AstonMartin extends Car {}
Class Jaguar extends Car {}
Interface CarFactory {
Public Car makeCar(String b) throws Exception;
}
Comments
• Abstract Factory classes are often
implemented with the Factory Method
pattern.
• Can also be implemented using the
Prototype pattern.
• A concrete factory is often a Singleton.
5.11 Command
Name: Command
Problem: Need a flexible organization for
methods that allows them to be context
sensitive in a structured way.
Solution: Place behaviour /operation in an
own class instead of in a method.
Examples
• Undo. It’s difficult to undo effects of an
arbitrary method. Methods vary over time.
• Choose menu option. Whether an option
can be chosen at any time depends on many
factors.
Command Structure
Client
Invoker
1
Command
Execute()
1
Receiver
Action()
receiver
ConcreteCommand
Execute()
State
Receiver.Action()
• Client creates a ConcreteCommand object
and specifies its receiver.
• An Invoker object stores the
ConcreteCommand object
• The invoker issues a request by calling
Execute on the command. When commands
are undoable, ConcreteCommand stores
state for undoing the command before
invoking Execute
• ConcreteCommand object invokes
operations on its receiver to carry out request
aClient
aCommand
anInvoker
new Command(aReceiver)
storeCommand(aCommand)
Execute()
Action()
aReceiver
Comments
• Pattern replaces function pointers (passing
functions as parameters) which is not
available in some languages.
• Pattern allows a class to call a receivers
routine without knowledge of it. Gives high
degree of decoupling between caller and
callee.
Command (Cont.)
• Client:
Command command =
Command.getCommand (…);
• Command.execute();
• A Factory method first gives a Command
object (means object can depend on current
situation)
• Then call execution command execute()
class Command {
public void execute() {
if (check-something) { //menu item
selectable?
this.getParameters(); //preparation
getTarget1().action1(); //do something
}
else
// do something else,
// like other action or target
}
}
Related Patterns
• A Memento pattern can be used the keep
the state a command needs to undo its
effect.
• A command that must be copied before
being placed on the history list acts as a
Prototype pattern.
Guidelines Checklist
•
•
•
•
Is there a pattern that addresses my problem?
Does the pattern provide an acceptable solution?
Is there a simpler solution? (pattern overuse)
Is the context of the pattern consistent with my
problem?
• Are the consequences of using the pattern
acceptable?
• Are there forces in my environment that conflict
with the use of the pattern?
Benefits and Dangers
+ support software reuse
+ language for discussing high-level problems
+ access to experience and knowledge
- limit creativity?
- needs a culture of reuse
- needs organisational education
Download