Gang of Four

39
More Design Patterns Wednesday, 31 October 12

description

g

Transcript of Gang of Four

Page 1: Gang of Four

More Design Patterns

Wednesday, 31 October 12

Page 2: Gang of Four

More Design Patterns

• 1. Adapter

• 2. Factory Method (& Abstract Factory)

• 3. Singleton

• 4. Observer

• 5. Command (& Command-Holder)

Wednesday, 31 October 12

Page 3: Gang of Four

1. Adapter

• problem:

• you want to re-use an existing off-the-shelf component in your design, but it doesn’t quite fit your needs

• its code cannot be changed

• solution:

• create an Adapter class which can act as an intermediary

Wednesday, 31 October 12

Page 4: Gang of Four

Real Life Example

• problem:

• a socket wrench can turn 25mm bolts (has female 25mm socket)

• you want to turn a 12mm bolt (has male 12mm head)

• solution:

• attach a ‘25mm (male) to 12mm (female)’ adapter to the wrench

• now your wrench can turn 12mm bolts. Yay!

Wednesday, 31 October 12

Page 5: Gang of Four

Coding Example: Rectangle

• a LegacyRectangle takes (topLeft, topRight, width, height) as parameters

• but the client wants to pass (topLeft, topRight, lowerLeft, lowerRight)

• we can build an adapter (or wrapper) Rectangle class which allows this:

• the wrapper takes the client’s request and repackages it for LegacyRectangle

from http://sourcemaking.com/design_patterns/adapter

Wednesday, 31 October 12

Page 6: Gang of Four

How to Apply

• identify the classes which need to connect

• the client and the adaptee

• identify the interface which the client requires

• design a wrapper class which provides the interface required by the client:

• it will have an instance of the adaptee as an attribute

• it will map the client interface to the adaptee interface

• the client can now use the new interface provided by the wrapper class to access the functionality of the adaptee class.

Wednesday, 31 October 12

Page 7: Gang of Four

Comment

• adapter is a form of polymorphism (see Grasp Part 2)

• adapters are used when there is an existing, immutable component

• if the component is mutable then consider changing the code or using an interface (see polymorphism steering example)

Wednesday, 31 October 12

Page 8: Gang of Four

2. Factory Method

• problem:

• how do we create different kinds of subclass without:

• exposing the instantiation logic to the client?

• forcing the client to be aware of the different subtypes?

• solution:

• we use a Factory class which creates concrete subtypes for the client

Wednesday, 31 October 12

Page 9: Gang of Four

Implementation

• the client needs a new Product, so it asks the factory object for a new Product, providing information about the type of Product it needs

• the factory instantiates a new Concrete Product and returns it to the client (casted to abstract Product class)

• the client uses the Products it is given as abstract Products without being aware of their concrete implementation

• we can add more products (subtypes) without altering the client’s code

from http://www.oodesign.com/factory-pattern.html

Wednesday, 31 October 12

Page 10: Gang of Four

Example: Shapes

• a graphical application:

• client: drawing framework

• products: shapes

• abstract Shape class defines the draw and move operations which must be implemented by the concrete shapes

• for example, the user selects to create a circle and specifies its radius

• the framework receives the parameters “circle” and “2.5” and asks the factory to create a shape based upon them

• the factory creates a new Circle and returns it to the client cast as an abstract Shapeadapted from http://www.oodesign.com/factory-pattern.html

DrawingFramewk

Shape

Circle createShape( String type, double [] parameters)

Wednesday, 31 October 12

Page 11: Gang of Four

Abstract Factory Pattern

extends the factory method by providing the interface to create a family of related objects without needing to explicitly refer to their classes:

declares an interface for operations which create abstract Products

implements operations to make concrete Products

declares an interface for a type of Product object

• defines a Product which will be created by the corresponding Concrete Factory• implements the AbstractProduct interface

uses the interfaces declared by the AbstractFactory and AbstractProduct classes

adapted from http://www.oodesign.com/factory-pattern.html

Wednesday, 31 October 12

Page 12: Gang of Four

Implementation

• AbstractFactory:

• determines the actual types of each concrete object and creates them

• returns abstract pointers to the objects created

• Client:

• knows nothing about the actual object’s creation

• has no need for class declarations relating to the concrete types

• Example: a global vending system:

• Orders are created and need to record customers’ Address and ContactPhoneNumber

• those objects will have differing formats depending upon which country the customer lives in

• so we can create factories for each country (or format), and point the Order class to the correct one based upon the customer’s place of residence

Wednesday, 31 October 12

Page 13: Gang of Four

Issues

• Pros:

• isolates creation of objects from the client, making manipulation easier

• when we need to exchange product families, the only change we need to make in the client code is to make it use the new factory

• Cons:

• adding new products to existing factories is difficult

• because we have to change the AbstractFactory interface and all its subtypes

Wednesday, 31 October 12

Page 14: Gang of Four

3. Singleton

• problem:

• sometimes we just want a single instance of a class

• examples:

• a print handler

• a factory which issues unique ids to the objects which it creates

• so what do we do if several clients need to be able to see a single instance of a class and only a single instance?

• solution:

• we create a Singleton which provides a global and single point of access to the class

Wednesday, 31 October 12

Page 15: Gang of Four

But what is the problem?

• if lots of clients need visibility to a single instance of a class, then we could just achieve that by:

• passing the reference to it around all those classes

• initialise all objects which need visibility with a permanent reference

• both do-able, but very inconvenient

• it’s far easier to instead provide a globally visible access point to the single instance

• providing we take care to ensure its uniqueness...

• which leads to one final question:

• if we only need one instance of a class in our design, used by many objects, then who should create it?

• let it create itself!

• and provide that single instance through a static getInstance() method

Wednesday, 31 October 12

Page 16: Gang of Four

Example

MoleculeFactory

instance : MoleculeFactory

- MoleculeFactory()+ getInstance() : MoleculeFactory

public static MoleculeFactory getInstance(){

if ( instance == null ){

instance = new MoleculeFactory();}return instance;

}

the underlining tells us that the attribute or method is static

• the constructor is private• so other objects can only create an instance of this class through the publicly visible getInstance() method

Wednesday, 31 October 12

Page 17: Gang of Four

Lazy or Eager?

• notice that the single instance is not initialised until the getInstance method is called

• this is Lazy Initialisation

• why not use eager initialisation instead?

• lazy initialisation is preferred because:

• creation work is avoided if the instance is never actually accessed during runtime

• initialisation could require complex or conditional creation logic

Lazy Initialisation:

public static MoleculeFactory getInstance(){

if ( instance == null ){

instance = new MoleculeFactory();}return instance;

}

Eager Initialisation

instance = new MoleculeFactory();...public static MoleculeFactory getInstance(){

return instance;}

Wednesday, 31 October 12

Page 18: Gang of Four

Use Static Methods?

• why don’t we just make all of the singleton’s methods static and publicly visible, thus avoiding instantiation altogether?

• using a instance with non-static methods is better:

• it permits subclassing

• it permits overriding, which (usually non-polymorphic) static methods don’t allow

• can avoid the “cannot make a static reference to the non-static method [blah]” coding error

Wednesday, 31 October 12

Page 19: Gang of Four

Issues

• a global access point means that the singleton is explicitly represented by its class name at many points in the code

• if we replace or rename it then every reference to it must be replaced or renamed too

• if the singleton implements the Serializable interface then it is possible to create multiple instances through serialization then deserialization

• implementing readResolve() avoids this

Wednesday, 31 October 12

Page 20: Gang of Four

Issues

• need extra care to ensure that only one instance is initialised if your code is multi-threaded

• use a lock. In java:

• public static synchronized MoleculeFactory getInstance()

• although double-locking is better

Wednesday, 31 October 12

Page 21: Gang of Four

4. Observer

• problem:

• a lot of objects need to know when a change happens to another object’s state

• solution:

• define a one-to-many dependency between objects so that when the state of one object (the subject) changes then all the dependant objects (the observers) are automatically notified

Wednesday, 31 October 12

Page 22: Gang of Four

But what is the problem?

• sometimes tightly coupling a lot of classes to a subject class is a bad idea:

• we have to write code to explicitly update those classes whenever the subject changes, maybe spread across several methods or classes

• if more classes need to change then we have to add more code to our program to follow any changes to the subject

• not every observing class will need to update every time

• so keeping a track of which classes need to update and when is difficult

• it would be better if the subject simply:

• allowed other objects to subscribe to it, and then

• notified its subscribers whenever its state changes

Wednesday, 31 October 12

Page 23: Gang of Four

Observer PatternObserver

<<interface>>

notify( Subject, Object) : void

Subject<<abstract>>

observers : ArrayList<Observer>

register( Observer) : voidunregister( Observer) : voidnotifyObservers( Object) : void

public interface Observer{

public void notify( Subject subject, Object argument);}

abstract class Subject{

protected ArrayList<Observer> observers;public void register( Observer obs){

observers.add( obs);}public void unregister( obs){

observers.remove( obs);}public void notifyObservers( Object argument){

Iterator iterator = observers.iterator();while ( iterator.hasNext() ){

Observer observer = iterator.next();observer.notify( this, argument);

}}

}

Wednesday, 31 October 12

Page 24: Gang of Four

Example: ebay listings

• whenever the current highest bid for an item ends:

• the item’s display listing will need to be updated

• so too will the persistent record

• watchers will need to be notified

• by email

• through their account summary

• the seller, current highest bidder and previous highest bidder need to be told too

• the nature and frequency of these updates will depend upon each customer’s contact preferences

• so, potentially a lot of conditional code to create and handle

• but the observer pattern vastly simplifies this

Wednesday, 31 October 12

Page 25: Gang of Four

Example: ebay listings

Observer<<interface>>

notify( Subject, Object) : void

Subject<<abstract>>

observers : ArrayList<Observer>

register( Observer) : voidunregister( Observer) : voidnotifyObservers( Object) : void

Item

itemId : IDdescription: StringcurrentHighestBid: Money

...

DisplayListingUI

...

...

Customer

...

...

Seller

...

...

ItemsDB

...

...

• when the value of currentHighestBid changes, responsibility for which observers need to act and how is handled by the observers themselves• Item merely tells them that its state has changed

• since Item only implements an interface it can also be sub-typed• but what if we want to make Customer and Seller subtypes of User?

observe

Wednesday, 31 October 12

Page 26: Gang of Four

Benefits

• coupling is minimised:

• the subject doesn’t know anything about its observers

• only that it has a list of observers

• the observers don’t know about each other

• but behave as if they do

• when one changes, so does another

• so we achieve abstract, minimised coupling

Wednesday, 31 October 12

Page 27: Gang of Four

Benefits

• updates can be broadcast:

• when the subject changes it notifies all observers

• without needing to specify each receiver

• and we can add or remove as many observers as we like

• reactions can be conditional:

• observers get to choose which notifications to respond to, how to respond and which to ignore

• in the ebay example this can be on an object-by-object basis for the customer class

Wednesday, 31 October 12

Page 28: Gang of Four

Problems

• timing issues:

• in a multi-threaded program observers might update out of desired order

• for example, web page says ‘item in stock’ before the database gets updated

• we might accidentally notify observers before we have finished updating the subject (easier to do than you’d think)

• without care we could also cause recursive notifications

Wednesday, 31 October 12

Page 29: Gang of Four

Problems

• performance issues:

• an update could cause a cascade of notifications (especially where some observers are also subjects for their own sets of observers)

• we can mitigate this by allowing observers to register to specific events within the subject

• subject is an abstract class, not an interface:

• java won’t allow multiple (abstract) inheritance

• if your subject must be a sub-type of another class then you’ll need to explicitly code the Subject methods and list of observers into it

Wednesday, 31 October 12

Page 30: Gang of Four

Problems

• who should call notifyObservers()?

• it could be a private method, called by the subject

• but that could be inefficient

• for example: multiple successive changes happen to the subject’s state

• we could let clients call the method instead

• but that makes errors more likely

Wednesday, 31 October 12

Page 31: Gang of Four

5. Command

• problem:

• one class in the user interface is usually responsible for listening to user actions

• it often also becomes the repository for all the logic which responds to user actions

• this leads to large, incohesive classes

• it violates the principle of separation of concerns

• solution:

• assign responsibility for the responses to small, functionally distinct Command classes

Wednesday, 31 October 12

Page 32: Gang of Four

Command Interface

• all the working code resides within, or is called from, the execute() method

• this presents a common interface to clients, reducing the need for conditional handling of different methods for different objects

public interface Command{

public void execute();}

Wednesday, 31 October 12

Page 33: Gang of Four

Example: Control Buttons

start pause resume

without using Command:

inside the main UI class:

public void ActionPerformed( Event event){

if ( event.getSource.equals( startButton) ){

simulation.start();}else if ( event.getSource.equals( pauseButton) ){

simulation.pause();}else if ( event.getSource.equals( resumeButton) ){

simulation.resume();}.... // and so on for all other UI events

}

using Command:

inside the main UI class:

public void ActionPerformed( Event event){

((Command) event.getSource()).execute();}

inside a typical button class:

public StartButton extends JButton implements Command{

public void execute(){

simulation.start();}

}

Wednesday, 31 October 12

Page 34: Gang of Four

...better, but still problems

• we have separated the details of the commands from the main UI

• but they are still tightly coupled to the individual UI components which trigger them

• and we might want to trigger a command from multiple components

• or even from some other source (e.g. control code)

• we might want to alter the command triggered by a component

• so we should use the CommandHolder interface

Wednesday, 31 October 12

Page 35: Gang of Four

CommandHolder Interface

• all the working code now resides within separate Command classes

• the CommandHolder classes (usually UI components) only need to know that they hold a Command, not what it does

• when a client requests a Command from a CommandHolder using getCommand(), the CommandHolder simply passes the Command to the client

public interface CommandHolder{

public void setCommand( Command command);public Command getCommand();

}

Wednesday, 31 October 12

Page 36: Gang of Four

Example: Control Buttonsstart pause resume

using CommandHolder:

inside the main UI class:

public void ActionPerformed( Event event){

((Command) event.getSource().getCommand()).execute();}

typical button class:

public StartButton extends JButton implements CommandHolder{

Command myCommand;public void setCommand( Command command){

this.command = command;}public Command getCommand(){

return Command;}

}

typical Command class:

public StartCommand implements Command{

public void execute(){

simulation.start();}

}

and because we can easily swap the command held by a button, we have the opportunity to replace the three buttons with one, de-cluttering the user interface

Wednesday, 31 October 12

Page 37: Gang of Four

Benefits

• application logic fully separated from the UI

• allows contextual use of components:

• can switch the commands which they invoke, even disable them

• allows commands to be maintained and invoked away from the UI

• if we record the list of commands so far invoked then we can often implement an Undo command

Wednesday, 31 October 12

Page 38: Gang of Four

To conclude

• the five (and a bit) patterns investigated here build upon the core GRASP principles

• taken together they can lead to clean, cohesive, lightly coupled code

• easy to read

• easy to re-use

• easy to change

• you can create your own java libraries for some of the interfaces

• as always, use appropriately

• some small, one-off projects won’t need this degree of flexibility

Wednesday, 31 October 12

Page 39: Gang of Four

References & Further Reading

• Adapter

• http://sourcemaking.com/design_patterns/adapter

• Factory Method

• http://www.oodesign.com/factory-pattern.html

• http://www.oodesign.com/abstract-factory-pattern.html

• Singleton

• http://www.ibm.com/developerworks/java/library/j-dcl/index.html

• Observer Pattern

• http://www.research.ibm.com/designpatterns/example.htm

• Command Holder

• Java Design Patterns: A Tutorial (JW Cooper 2000)

Wednesday, 31 October 12