CSCD01 Engineering Large Software Systems Design Patterns Joe Bettridge Winter 2018 With thanks to Anya Tafliovich
Design Patterns Design patterns take the problems consistently found in software, and look to solve them using a reusable design. These patterns describe the way code is laid out, rather than the exact code that would be required This implies that design patterns are language agnostic to a degree We can use UML to easily describe these patterns both structurally and functionally These patterns also represent a means to communicate design decisions which may have been made by other developers, in a common and clean way. It is important to get used to recognizing these within a given code base.
Design Patterns First published in a book titled Design Patterns: Elements of Reusable Object-Oriented Software in 1994, although the concept had been around since the late 70 s. The book was published by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides) The original book had 23 patterns, there have been many more created since. The patterns are split in three main groups: Creational Patterns that deal with the mechanics of object creation Structural Patterns that deal with creating simple ways of building relationships between objects Behavioural-Patterns that deal with common communication between objects
Design Patterns Slide Layout For the next several lectures, we will be diving into each of the patterns laid out by the gang of four in detail. For each pattern, we will discuss its intended use, the motivation of the pattern, the UML that describes it, and the situations to look for when using it. For some patterns, we will also be going into specific examples in Java or Python, as well as consequences of using it, and common or known issues with the use of the pattern.
Gang of Four Patterns Original book describes 23 patterns 5 Creational, 7 Structural, and 11 Behavioural. Creational Patterns Behavioural Patterns Structural Patterns Abstract Factory Chain of Responsibility Adapter Builder Command Bridge Factory Method Interpreter Composite Prototype Iterator Decorator Singleton Mediator Façade Memento Flyweight Observer Proxy State Strategy Template Method Visitor
Observer (B) Problem Need to maintain consistency between related classes Two aspects that are dependent upon one another Objects should be able to updated related objects without requiring specific knowledge of those objects Intent Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and update automatically Consequences There is only light, abstract coupling between the Subject and Observer. Since the Subject only knows it has a list of Observers whom conform to the simple Observer Interface Broadcast messaging is achieved, as the Subject does not need to specify the receiver of the message Not easy to trace the cost of an update, as everything is so loosely coupled at a design level, but is highly interdependent at an operation level. Each change to the Subject may cause large cascading changes throughout application, if not carefully controlled for Related Patterns Mediator, Singleton
Observer Standard Solution
Observer Java Implementation Although Java does provide a default Observer implementation, it does so through an abstract class. This removes the ability to use it alongside custom hierarchies, as Java does not have multiple inheritance. For this reason, most implement their own version of the pattern classes using interfaces.
Observer Example in Java
Observer Sequence Diagram The standard sequence diagram for Observer is shown to the right. You may also see this drawn without the Par tag.
Singleton Pattern (C) Problem How do you ensure that only one instance of a class ever exists? Is there a way to ensure that an object is only created if it is needed? Intent Ensure a class only has one instance and provide a global point of access for it Consequences Strict control on access since the singleton has only one point of entry, this can be easily monitored and controlled Reduced namespace The pattern removes pollution of the global namespace by unnecessary repetition Recent thoughts on Singleton A large number of software engineers now consider Singleton to be a design smell, something that is off in the system. Seeing it used often means something was not well thought out. A notable person with this thought is Erich Gamma, the original creator of the pattern Related Patterns Many patterns can use singleton in their implementation, but this is becoming frowned upon
Singleton Standard Solution
Iterator Pattern (B) Problem Want to be able to see the objects stored within an aggregator sequentially, but do not want to expose the underlying representation Want to have the ability to iterate over the same aggregation in different, independent ways Intent Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation Consequences Supports variations in the traversal of an aggregate. Complex aggregates may be traversed in many ways Iterators simplify the aggregate interface by removing details about traversal More than one traversal can be pending on an aggregate. Iterators only keep track of their own traversal state, and thus, multiple traversals can be occurring in unison Related Patterns Composite, Factory Method, Memento
Iterator Pattern Standard Solution
Iterator in Java In java, you will notice that Iterators are most commonly seen with classes that have generics. The iterator pattern is implemented in Java already through the Iterator Interface within java.util package Since Java 5, using the Java Iterable interface allows for you to use foreach loops
Strategy Pattern (B) Problem Having multiple classes that only differ in the algorithms used on them (behaviour) Algorithms shouldn t be implemented directly within the class Intent Define a family of algorithms, encapsulating each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it Consequences Families of related algorithms emerge these can be factored out using class hierarchies within the strategies An alternative to sub-classing Sometimes algorithmic differences are only difference between parent and children classes, Strategy removes the need to create specific children Eliminate conditional statements By delegating the choice to the composite class, remove the need for if blocks Choice of implementation Client can pick between multiple strategies that have different time or space trade-offs Clients must be aware of different strategies The pattern can potentially create issues if client doesn t have full awareness Communication overhead between strategy and context Context can create large overhead for simple algorithms that don t need the full set of information that other more complex algorithms need Increased number of objects As each strategy requires its own class, the number of objects can increase Related Patterns Flyweight Strategy often makes good Flyweights
Strategy Pattern Standard Solution
Example Without Strategy Pattern
Using Strategy Pattern
Façade Pattern (S) Problem Want a way to hide the complexity of an underlying package from those who use it Some programs have complexities we want to hide from other users Intent Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystems easier to use. (NOTE: In this context interface does not mean an interface type object such as we have in Java, but a point of communication between two areas) Consequences Clients are shielded from subsystem objects, reducing scope of what they need to understand Promotes weak coupling, between subsystems and clients of that system It doesn t explicitly prevent direct use of subclasses, but gives an alternative. Related Patterns Abstract Factory, Mediator, Singleton
This is a Façade
Façade Standard Solution The Façade does not add any new functionality, nor does it remove previously available functionality. It simply gives an easy to use interface into a subsystem that may have been previously difficult to understand.
Façade - Example
Adapter Pattern (S) Problem Clients often want things in a format other than what we have, but we do not want to recreate our classes Lets classes work together that otherwise couldn t easily work together by creating an agreed interface Two primary forms: Class adapter (using multiple inheritance) and Object adapter (using object composition) Intent Convert the interface of a class into another interface to meet a clients demand/expectation. Adapter lets classes work together that couldn t otherwise because of incompatible interfaces Consequences Each of the two versions have different consequences which will be broken down on the following slide Related Patterns Bridge, Decorator, Proxy
Adapter Two Forms Class Adapter Adapts Adaptee to Target by committing to a concrete Adaptee class. As a consequence, a class adapter won t work when we want to adapt a class and all its subclasses Allows for overriding the Adaptee s behaviour Object Adapter Lets a single adapter work with many adaptees, for example, all subclasses of the adaptee as well as the adaptee itself Makes it difficult to override the methods of the adaptee Consequences How much adapting should be done It can be difficult where to draw the line for when this is an appropriate pattern and when it will end up ultimately creating more work Pluggable adapters a class is more resuable if you minimize the assumptions other classes make to use it. The term refers to building in adapters from the onset Using two-way adapters currently adapter does not allow for two-way adaptation, and it isn t transparent to the client what is happening. This can lead to suboptimal situations
Adapter Standard Solution Class Adapter Object Adapter
Adapter - Example PROBLEM Suppose there is a shortage of Ducks, and in their place we want to use Penguins, as I mean, they are pretty close What cannot be done Direct substitution of Penguins where we have Ducks. Ducks have some distinctive differences from Penguins, and thus have a different interface! Solution Write a PenguinAdapter class! (Can you even tell which is which?)
Adapter - Example
Adapter - Example
Factory Method Pattern (C) Problem Creating new objects often requires complex logic, which we d ideally like to mask from our clients Often we want to create objects in a fixed way but don t want to store this fixed logic inside the calling class as this creates stronger coupling Intent Define an interface for creating an object but let subclasses decide which class to instantiate. Factory method allows classes to differ instantiation to subclasses Consequences Provides hooks for subclasses Creating objects in a class with a factory method is more flexible Connects parallel class hierarchies Factory methods can be called from either creators or from parallel classes Related Patterns Abstract Factory, Template Method, Prototype
Factory Method Standard Solution
Factory Method - Example