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