Design Patterns

Motivation, Best Practice

About Patterns

Definition

„Pattern“ has been defined as „an idea that has been useful in one practical context and will probably be useful in others.“

Elements of a pattern

  1. Name - Aliases, classifications
  1. Motivation and problem statement
  1. Context
  1. Solution

    - Structure

    - Participants

    - Collaboration

    - Consequences

    - Implementation

    - Examples

Usage in Software Development

Advantages

Common vocabulary → helps manage complex systems, better communication

Improves documentation

Capture knowledge and make it more widely available

Combination of patterns

Reusability, adaptability, extendability → Minimizes development time and costs

Disadvantages

Patterns need to be adapted to the code context

Only indirect code reuse

deceptively simple

Teams may suffer from pattern overload

Classification of Patterns

  1. Architectural Patterns

    – Structure of software systems – Subsystems, dependencies, communication

  1. Design Patterns

    – level of classes – Snippets focus on low-level details, Programming language specific

  1. ProtoPatterns

    – Particular case

  1. Antipatterns

    – Commonly used but should be avoided

When to use

Similar problems that recur with variations in different contexts

Patterns can be an overkill if solution is simple linear set of instructions

Pattern Types: Architectural Patterns (Overview)

  1. Fundamental Patterns

    essential concepts of software architecture

    • Interface Pattern
    • Delegation Pattern
    • Immutable Pattern

  1. Creational Patterns

    initializing and configuring classes and objects

    • Singleton
    • Factory
    • Abstract Factory
    • Builder (Factory for building complex objects in different variants)
    • Prototype (Factory for cloning new instances from a prototypical instance)

  1. Structural Patterns

    decoupling "interface\lrarrimplementation" of classes and objects

    • Facade / Facet
    • Adapter
    • Proxy
    • Bridge (Abstraction for dynamically binding one of many implementations)
    • Composite (Treats objects and compositions uniformly)
    • Flyweight (Many fine-grained objects shared efficiently)

  1. Behavioral Patterns

    dynamic interactions among objects

    • Observer
    • Decorator
    • State
    • Strategy
    • Chain of Responsibility
    • Iterator (Aggregate elements are accessed sequentially)
    • Command (Object represents all the information needed to call a method at a later time)
    • Mediator (Mediator coordinates interactions between its associates)
    • Memento (Snapshot captures and restores object states)

Fundamental Patterns

○ Interface

Seperating description and implementation

Issue

Separate description and concrete implementation

defines the signature operations of an entity

implementations can be added / changed easily afterwards

should be stable - in comparison to implementation

○ Delegation

Extension of functionality without inheritance

Issue

Class needs additional functionality

Solution

Outsource functionality into third class and use its instance via delegation

  • Example 1

    Solution without inheritance:

    Notification-Service gets an instance of the object that should get called.

  • Example 2
    class A {
    void foo() {
    print("a.foo");
    }
    }class B {
    private delegate A a; // delegation linkpublic B(A a) {
    this.a = a;
    }void foo() {
    a.foo(); // call foo() on the a-instance
    }
    }
    a = new A();
    b = new B(a); // establish delegation between two objects

○ Immutable

Providing unchangeable object after initialization

Issue

Object instance should be immutable

Because several threads are accessing same object but object properties should be configurable

Solution

  1. Initialize variables in constructor
  1. Provide only read access with Getter-Methods getName(), getDate()

Creational Patterns

○ Singleton

Provision of a single instance only

Issue

Only one object instance should exist:

  • Database access
  • Id generator
  • Logger
  • Communication with hardware

Solution

  • Example
    public class Person {
    private final Logger LOG = LoggerFactory.getLogger(Person.class);
    Logger getLogger() {
    return LOG;
    }
    }

    In this case LOG is the same object even without static due to the way the LoggerFactory works.

○ Factory

Method in a derived class creates associates

Issue

Object creation & configuration is complex

Initialization of additional sub-instances required

Solution

  • Example
    interface Product { float getPrice(); }public class Milk implements Product {
    final float price;
    public Milk(final float price) { this.price = price; } //constructor
    public float getPrice() { return price; } //getter
    }public class Sugar implements Product {
    final float price;
    public Sugar(final float price) { this.price = price; } //constructor
    public float getPrice () { return price; } //getter
    }public class Product Factory {
    public static Product createProduct(String what){
    //When sugar is requested, we return sugar:
    if (what.equals("Sugar")) { return new Sugar(1.49F) ; }
    // When milk is needed, we return milk:
    else if (what.equals("Milk")) { return new Milk(0.99F); }
    // Otherwise return at least sugar
    else { return new Sugar(1.49F); }
    }
    }

○ Abstract Factory

Factory for building related objects without specifying their concrete classes

Issue

Achieving higher abstraction by grouping individual factories with a common theme

Solution

A group of individual factories that have a common theme

Two hierarchies → abstract AbstractFactory class provides interface

Client only knows abstract interface → Family may grow independently of the client

Structural Patterns

○ Facade / Facet

Simplifies the interface for a subsystem

Issue

Need simplified access to a complex subsystem

Provides an abstracted interface of a subsystem

Solution

  • Example
    public class SimpleMail {
    public static int sendMail(String address, String subject, String body) {
    int status = 0;
    ... //Complex mail sending operation
    return status;
    }
    }

○ Adapter / Translator

Adapts a server interface for a client

Issue

Need to integrate incompatible external functionality

Solution

Translates (data transformation) into a compatible interface

○ Proxy

One object approximates another

Issue

Need to integrate further actions before intended method call

Solution

Extends concept of the delegation pattern

Implements interface and acts as a representative of the „original“ implementation

Used in: security, logging, caching

○ Inversion of Control IoC

Die Verantwortung für das Erzeugen und Initialisieren von Objekten wird an eine zentrale Stelle (z.B. eine Klasse) delegiert.

Von der zentralen Stelle kann man die Abhängigkeiten zwischen den Objekten leichter überblicken und steuern.

Detailierter: Siehe Block 3 - Werkzeuge

Behavioral Patterns

○ Observer

Dependents update automatically when a subject changes

Issue

Need to react to state changes in an object

Solution

in case of changes of the instance‘s state execute specific action(s) – e.g., notification of instances interested in change

○ Decorator / Wrapper

extends an object

Issue

Need to extend object functionality during runtime (inheritance not possible during runtime)

Solution

Dynamically add new functionality to an existing object

  • Example
    Cake cake = new ChocolateCake();NutsInCake nic = new NutsInCake(cake) ;
    nic.setAmount(15) ;
    nic.setType("hazelnut") ;CandleCake cc = new CandleCake (nic) ;
    cc.setCandles(13);
    cake = (Cake) cc;
    cake.bake();
    VisualComponent vc = new ScrollBar( new Border( new TextEditor() ));
    vc.draw();
    Stream s = new FileStream(filename);
    Stream s = new CompressingStream( new BufferedStream(new FileStream(filename) ));

○ State

Object whose behavior depends on its state

Issue

Need to change object behavior based on current state

Solution

Allow an object to update its behavior when its internal state changes

(internal state gets changed with a setState() method)

○ Strategy

Vary algorithms independently

Solution

Dynamically add new algorithms → context chooses algorithm to use

  • Example
    class NotificationManager {
    public enum NotificationMethod {SMS, EMAIL};
    private List<Person> members;
    public void addMember(Person person, NotificationMethod notificationPref){
    members.add(person);
    INotification notification;
    if (notificationPref == NotificationMethod.SMS)
    notification = new Sms();
    else
    notification = new Email();
    notification.setPerson(person) ;
    person.setNotificationPreference(notification);
    }public void sendNotifications (String message)
    for (Person p : members)
    p.sendMessage(message);
    }
    }

○ Chain of Responsibility

Request delegated to the responsible service provider

Issue

Improve loose coupling between a series of processing logic

Solution