DESIGN PATTERNS


Context:


Most of the important works in this field are due to:

  • Gamma, Helm, Johnson, Vlissides.
  • Small Talk  came up with Model/View/Control (MVC).
  • Analysis Patterns by Fowler which are very useful during the initial stages of the software development.
  • Architectural Patterns by Mary Shaw, Garlan, Schmidt.
  • Gamma's definition of Design Patterns:
    Catalog of Design Patterns:
    Design patterns can be classified into different families based on two criteria:

    Purpose:    This reflects what a pattern does. The three classifications of design patterns based on purpose are:

    Scope:    This specifies whether the pattern applies primarily to classes or objects. Based on scope criterion, patterns are organized into:
                The table given below summarizes the design pattern space.

     
     
    Scope\Purpose Creational Pattern Structural Pattern Behavioural Pattern
    Class Factory Method Adapter(class) Interpreter
    Template Method
    Object Abstract Factory
    Builder
    Prototype
    Singleton
    Adapter(object)
    Bridge
    Composite
    Decorator
    Facade
    Flyweight
    Proxy
    Chain of Resposibility
    Command
    Iterator
    Medicator
    Memento
    Observer
    State
    Strategy
    Visitor

     
     
    Describing Design Patterns:
    Pattern Name and Classification: A good name is vital since it conveys the essence of the pattern.

    Intent: The purpose of the pattern, its rationale and the design issues it address are stated.

    Also Known As: Other well known names of the pattern, if any.

    Motivation: A scenario that illustrates a design problem is presented and shows how the class and object structures in the pattern solves it.

    Applicability:The situations where the pattern can be used and how to identify those situations are described.

    Structure: A graphical representation  of the classes in the pattern using the notaion based on the Object Modelling Technique(OMT). Also interaction diagrams can be used to illustrate the sequences of requests and collaborations between objects.

    Participants:  The classes and/or the objects participating in the design pattern and their responsibilities.

    Collaborations: How the participants collaborate to carry out their responsibility.

    Consequences:
                    How does the pattern support its objectives?
                    What are the trade offs and results of using this pattern?
                    What aspect of the system structure does it let you to vary independently?

    Implementation:

    What pitfalls, hints, or techniques should you be aware of when implementing the pattern?
    Are there language-specific issues?
    Sample Code: Code fragments that illustrate how to implement the pattern.

    Related Patterns:

    What design patterns are closely related to this one?
    What are the important differences?
    With which other patterns should this one be used?
    Known Uses: Examples of the pattern found in real systems.
    Why Design Patterns?
    Enable best practises to be used commonly.
     use composition over inheritance. (Patterns like Composite, Decorator, COR, mediator, Observer, Strategy etc uses this practise)
     program to interface rather than implementation.
     use interface inheritance rather than implementation inheritance.
     use a judicious mix of composition and inheritance.
    Find appropriate objects during design.
    The task of decomposing a system into objects is influenced by a number of factors such as encapsulation, granularity, dependency, flexibility, performance, ....
    Design patterns help to identify the less obvious abstractions and objects during the design phase of the software development process.
    Example: Composite and Strategy.
    Determine the granularity of the object.
     Granularity refers to the level of detail to be included with an object.
     An object can represent everything down to the hardware or all the way up to entire applications.
      Design patterns like Facade and Flyweight addresses this issue of granularity.
    Specify object interfaces.
    The interface of an object represents the set of requests that can be sent tot the object.
    Design patterns help to identify the key elements in the interface, the kind of data exchanged and the relationships between interfaces.
    Example: Memento.


    Specify object implementation.

    Design patterns help to ensure that the system is written in terms of interface, not in terms of implementation.
    Example: Chain of Responsibility, Composite, Strategy, State, Command, Observer.
    Effective use of reuse mechanism.
  • Inheritance
    • Inheritance results in white-box reuse where the internals of the parents are visible to the subclasses.  Hence inheritance breaks encapsulation.
    • It is defined statically at compile-time and hence implementations cannot be changed at run time.
    • It makes it easier to modify the implementation to be reused.
    • It can lead to explosion of subclasses.
  • Composition
    • New functionality is obtained by assembling objects.
    • Composition leads to black-box reuse since the internal details of the objects are not visible.
    • It is dynamic in nature and hence implementation can be changed at run time.
    • A design based on object composition have more objects and inter-relationships between them instead of being defined in a single class.
  • Delegation
    • Helps to make composition as powerful a way for reuse as inheritance by composing behaviors at run time.
    • Two objects are involved in handling a request: a receiving object and a delegate.
    • The receiving object delegates operations to the delegate and passes itself to the delegate so that the delegated operation can refer to the receiver.
    • Dynamically highly parameterized software is harder to understand.
    • Run time inefficiencies  also exist.
    • Design patterns like State, Strategy, Visitor, Mediator etc. uses delegation.
  • Parameterized types
    • Also called generics or templates.
    • It helps to define a type without specifying all the other types it uses.  The unspecified types are provided as parameters. For example, if we define a new type as List, a list of integers  can be created by passing "int" as parameter and for creating a string list "string" is passed as parameter.
    • It cannot change at run time.


    Relate run-time and compile-time structures better.

  • It is often very difficult to find a one-one mapping between run-time structure and code structure. Design patterns are very helpful in capturing the distinction between the compile-time  and run-time structures explicitly. They facilitates reverse engineering.
  • Example: Composite, Chain of Responsibility, Decorator, Observer.
  • Helps to come up with excellent documentation.

    Enable design for change.


    Helps in the design of application programs, toolkits and frameworks.

    • It enables the design of high quality application programs by
      • Promoting internal reuse by reducing dependencies.
      • Enhancing extensibility by exploiting composition and reduced coupling.
      • Making the application more maintainable.
    • Toolkit is a set of related and reusable classes to provide useful and general purpose functionality. It enables reuse of code. (Example: set of classes for stacks, lists etc.) Dependencies and assumptions that limit the flexibility and applicability of the toolkit should be avoided.
    • A framework is a set of cooperating classes that make up a  reusable design for a particular domain(Example: finance, graphics ...). Abstract classes  will be present and to customize a particular application, create application-specific subclasses. Here, the emphasis is on design reuse. Framework results in the fast development of the application, but much of the creative freedom is lost since most of the design decisions are made by it. The key points to be noted in the design of framework are extensibility, flexibility and reduced coupling. Inspite of the similarities between design patterns and framework, they differ in three major ways.
      • Design patterns are more abstract than framework: A framework can be reused whereas design patterns have to be implemented each time they are used.
      • Design patterns are smaller architectural elements than framework: A framework can include several design patterns while the reverse is never true.
      • Design patterns are less specialized than framework: A framework always has a particular application domain.
    Document Editor: A Case Study
     
     
    Requirements Specification:
    1.     Document Structure:    Treat characters, lines, rows and columns uniformly.
    2.    Formatting:    It should be possible to dynamically switch between different formatting algorithms.
    3.    Embellish the user interface in a very flexible and dynamic way.
    4.    Support multiple look and feel standards:    Lexi should easily adapt to multiiple look and feel standards like Motif, PM etc.
    5.    Support multiple windowing systems:    Lexi should be independent of the windowing systems used.
    6.    Support flexible user operations.
    7.    Spell check and hyphenation.
    Document Structure:
  • A document is an arrangement of basic graphical elements such as characters, lines, polygons and other shapes.
  • The basic idea used to compose a document is that of recursive composition.
  • Recursive composition is the technique by which we build complex elements out of simpler ones.
  • It uses a mix of composition and inheritance.
  • For example, a set of characters and graphics are arranged to form a row, multiple rows are arranged to form a column, multiple columns can form a page and so on.
  • The design pattern, Composite captures the essence of recursive composition in object-oriented terms.
  •          The resulting object structure is as shown below.

     
     
    We define an abstract class, Glyph, to represent all the objects that can appear in a document. It provides three operations- Draw(Window) draws itself in the window, Intersects(Point) returns checks whether the glyph is intersecting with the point p and Insert(Glyph, int) inserts the Glyph at position 'int'. The partial Glyph class hierarchy is shown below. Here Character, Polygon and Rectangle are the leaves and Row represents the composite.
    Formatting:
     
  • Usually different formatting algorithms are used within the same document structure.
  • It should be possible to switch between different algorithms.
  • An important trade-off to consider in this case is the balance between formatting speed and formatting quality.
  • The formatting algorithms should be completely independent of the document structure ie, they should not change with change in the document structure.
  • Conversely, addition of a new algorithm shouldn't require the modification of the existing glyphs.
  • Main idea used here is the encapsulation of algorithms using objects.
  • Strategy is best suited for encapsulating algorithms and dynamically switching between them.
  • In the class diagram show below, whenever an object of type Composition is created, a Compositor is also created, which is responsible for choosing tha appropriate algorithm.
  • Here Composition is the context, Compositor is the strategy and the concrete strategies are ArrayCompositor, TeXCompositor and SimpleCompositor.
    Embellishing User Interface:
     
  • It should be possible to add and remove embellishments dynamically.
  • The main idea used is that of transparent enclosure.
  • This concept combines the notions of single child composition and compatible interfaces.
  • The design pattern, Decorator, gives emphasis to transparent enclosure and single child composition.
  • Embellishments such as borders and scrollbars can be added to the above document editor as shown in the class diagram below.
  • Here the decorator is Monoglyph and the concrete decorators are Border and ScrollBar.
  • Responsibilities can be easily added and detached dynamically using the structure given below.
  •                 Monoglyph serves as an abstract class for embellishment glyphs such as borders and scrollbars. The resulting object structure is as shown below.
     
    Adding  multiple look and feel standards:
  • It should be possible to support multiple look and feel standards like Presentation Manager, Motif, Mac.
  • Each of these provide standard scrollbars, buttons and menus.
  • Main idea used here is to postpone the creation of objects till they are required and to create them indirectly.
  • Abstract Factory can be used for abstracting the process of object creation.
  • Normally, we create an instance of the MotifFactory class using the following code:
  •  
    ScrollBar *sb = new MotifScrollBar;

    Here, the client is tied to a particular look and feel standard namely, Motif. This can be avoided using the following code.

    ScrollBar *sb = guiFactory->CreateScrollBar();
    GUIFactory *guiFactory = new MotifFactory;
     

  • The resulting GUIFactory hierarchy is as shown below. The Abstract Factory is WidgetFactory, the concrete factories are MotifWidgetFactory and PMWidgetFactory and the abstract products are Window and Scrollbar.
    Supporting multiple window systems:
  • There can be multiple windowing systems such as Windows, X, Presentation Manager etc.
  • Abstractions in this case are not as clear as in the case of look and feel standards. Hence Abstract Factory is not a good choice.
  • Bridge pattern helps to create two separate class hierarchies, one that supports the logical notion of windows and the other for capturing the different implementations of the windows.
  • It isolates abstraction from implementation.
  • The different operations, the window class should support are:
  • Two extreme philosophies can be considered:make the interface extremely rich with all the functionalities.take the minimum common functionality.
  • Neither extreme is a viable solution, so the window class will provide a convenient interface that supports the most popular features.
  • The resulting hierarchy of window abstractions separating the abstraction from implementation is as follows. The Abstraction is Window, Implementor is WindowImp, the concrete implementors are XwindowImp and PMWindowImp and the RefinedAbstractions are IconWindow and TransientWindow.
  • User operations: Spell Checking and Hyphenation: