1 / 115

TDDE45 - Lecture 2:

Martin Sjölund

Department of Computer and Information Science Linköping University

2021-08-25 2 / 115

Part I

Intro 3 / 115 Brief History (1)

General concept of patterns (253 of them, for architecture in the buildings sense):

Similarities between software design and architecture was noted by Smith 1987. 4 / 115 Brief History (2)

By 1995, the Design Patterns book by the Gang of Four was published (Gamma et al. 1995). Many of the patterns are based on existing idioms in programming languages. New patterns have been created over the years: Kind GoF Wikipedia Creational 5 10 Structural 7 12 Behavioral 11 15 Concurrency 0 16 5 / 115

Principles + Problem = Pattern 6 / 115

Principles = SOLID + Some general tips 7 / 115 Some general tips

1. Encapsulate what varies (S) 2. Program to an interface, not to an implementation (I, D) 3. Favor Composition over Inheritance (L) 4. Don’t call us, we’ll call you (O) 8 / 115 Some more tips

5. Depend upon abstractions, not upon concrete classes (see 2). 6. Strive for loosely coupled designs between objects that interact (see 4). 7. Only talk to your friends. 8. Avoid global variables (constants can be fine), static methods (thread-safe code). 9. Simple, readable code is often favorable over strictly adhering to the design principles. 9 / 115 Full instructions are on the course homepage

One of your tasks is to: Read specifically the Intent, Motivation, Applicability and Structure of 4design patterns per person in the Gang of Four course book (or the corresponding parts in another source such as Head First Design Patterns). 10 / 115 Structure of the book The Gang of Four book is very structured; the following is a summary of section 1.3: I Pattern name and classification (creational, structural, behavioral; class or object) I Intent I Also known as I Motivation I Applicability – what poor designs can this pattern solve? I Structure – graphical representation (using OMT – a predecessor to UML) I Participants – classes or objects in the design pattern I Collaborations – related to partcipants I Consequences – trade-offs? I Implementation – pitfalls, hints? I Sample code (C++ or smalltalk) I Known uses (from real code; you could of course list Eclipse on every design pattern) I Related patterns – many patterns do similar things; how do they differ? Which design patterns can you combine with it? 11 / 115

Part III

Some Design Patterns 12 / 115 You choose!

I Strategy I Builder I Factory Method I Adapter I Decorator I Bridge I Template Method I Observer I Composite I Chain of Responsibility I Abstract Factory (+ Dependency Memento Injection) I I Command I Singleton (+ example in Ruby) 13 / 115

Part IV

Strategy 14 / 115 Strategy

Strategy Context

Client 15 / 115 Strategy: Consequences

- Clients must be aware of different + Can choose implementation of a strategies strategy at run time - Communication required between + Eliminate hardcoded conditionals context and strategies + Avoids excessive subclassing - Potentially many strategy objects created 16 / 115

Part V

Factory Method 17 / 115 Factory method (before) 18 / 115 Factory method (before)

Pizza pizza = null; if (style.equals("NY")){ if (type.equals("cheese")){ pizza = new NYStyleCheesePizza(); } else if (type.equals("veggie")){ pizza = new NYStyleVeggiePizza(); } else if (type.equals("clam")){ pizza = new NYStyleClamPizza(); } else if (type.equals("pepperoni")){ pizza = new NYStylePepperoniPizza(); } } else if (style.equals("Chicago")){ if (type.equals("cheese")){ pizza = new ChicagoStyleCheesePizza(); } else if (type.equals("veggie")){ pizza = new ChicagoStyleVeggiePizza(); } else if (type.equals("clam")){ pizza = new ChicagoStyleClamPizza(); } else if (type.equals("pepperoni")){ pizza = new ChicagoStylePepperoniPizza(); } } else { System.out.println("Error: invalid type of pizza"); return null; } 19 / 115 Factory method 20 / 115 Factory method

+ Decouples clients from specific dependency classes - Requires keeping factory methods in + Eliminates hardcoded conditionals sync with domain classes + Connects parallel class hierarchies (NY*Pizza, Chicago*Pizza) 21 / 115

Part VI

Decorator 22 / 115 Decorator

Component

Beverage b = new Coffee(); b = new SweetenedBeverage(new SweetenedBeverage(b));

Decorator

return 5+beverage.cost(); 23 / 115 Decorator

+ Dynamically adds behavior to specific - Decorator objects are not of the same instances of a class type as the objects it comprises + Customizes an abstract class without - May result in many small objects knowing the implementations 24 / 115

Part VII

Template Method 25 / 115 Template Method

class Coffee{ public: void prepareRecipe(); void boilWater(); void brewCoffeeGrinds(); class Beverage { void pourInCup(); public: void addSugarAndMilk(); void prepareRecipe(); }; void boilWater(); class Tea{ void pourInCup(); public: // No brew==steep void prepareRecipe(); // No addCondiments void boilWater(); }; void steepTeaBag(); void pourInCup(); void addLemon(); }; 26 / 115 Template method: Consequences

+ Can isolate the extensions possible to an algorithm + Isolates clients from algorithm changes 27 / 115 Template method 28 / 115 Default implementations (hooks)

public abstract class CaffeineBeverageWithHook { void prepareRecipe() { boilWater(); brew(); pourInCup(); if (customerWantsCondiments()) { addCondiments(); } } boolean customerWantsCondiments() { return true; } }

public class CoffeeWithHook extends CaffeineBeverageWithHook { // ... public boolean customerWantsCondiments() { return getUserInput().toLowerCase().startsWith("y"); } } 29 / 115 Template method?

public class Duck implements Comparable { Duck[] ducks = { String name; new Duck("Daffy", 8), int weight; new Duck("Dewey", 2), new Duck("Howard", 7), public Duck(String name, int weight) { new Duck("Louie", 2), this.name = name; new Duck("Donald", 10), this.weight = weight; new Duck("Huey", 2) } }; public String toString() { Arrays.sort(ducks, new Comparator(){ return MessageFormat.format("{0} weighs {1}", name, weight); @Override } public int compare(Duck arg0, Duck arg1) { return new Integer(arg1.weight).compareTo(arg0. public int compareTo(Duck object) { weight); return new Integer(this.weight).compareTo(object } .weight); }); } } No Yes 30 / 115 Java 8: With inline lambda (not Template method)

Arrays.sort(ducks, (arg0, arg1) -> new Integer(arg1.weight) .compareTo(arg0.weight)); 31 / 115

Part VIII

Composite 32 / 115

Waiter

Diner menu print() printMenu()

Pizza Breakfast menu menu print()

Spam, Clam Cheese Coffee Ham & Spam & Eggs & spam & Pizza Pizza menu eggs eggs spam print() eggs

Dark roast Tea Espresso print() Coffee 33 / 115 34 / 115 Client

Component

Composite

Leaf 35 / 115 Composite: consequences

- Creates composite classes that violate + Allow us to treat composite objects the principle of a single responsibility and individual objects uniformly - The composite cannot rely on + Allows arbitrarily complex trees components to implement all methods 36 / 115

Part IX

Abstract factory 37 / 115 Ingredients Pizza Store Clients

Fresh Clam Mozzarella Cheese NY Thin Crust Dough I Want a Cheese Pizza

Frozen Clam Parmesan Cheese Chicago Thick Crust Dough 38 / 115 39 / 115 40 / 115 41 / 115 42 / 115 43 / 115

Concrete Factory

Abstract Factory

Abstract Products 44 / 115 Clients 45 / 115 Abstract factory: consequences

+ Isolates clients from concrete dependencies + Makes interchanging families of products easier 46 / 115

Strategy – behavioural Abstract factory – creational I When related classes only differ in behaviour I A system should be independent of how its products are created I You need different variants of an algorithm I A system should be configured with one of multiple families of products I An algorithm uses data the clients don’t need to know I You want to provide a class library of products, and only expose their I A class uses conditionals for selecting interfaces behavior 47 / 115 Design principles

I Encapsulate what varies I Program to an interface, not to an implementation I Favor composition over inheritance I Classes should be open for extension but closed for modification I Don’t call us, we’ll call you 48 / 115

Part X

Dependency Injection 49 / 115 50 / 115 : How?

1. Declare dependencies as constructor arguments of interface types 2. Register classes (components) in an Inversion-of-Control Container 3. Resolve the top-level object from an interface through the Container 51 / 115 1. Dependencies namespace DITest { public class FancyClamPizza: IClamPizza { private IClam clam; private ICheese cheese; public FancyClamPizza (IClam clam, ICheese cheese) { this.clam = clam; this.cheese = cheese; } public String ClamType() { return String.Format("fancy {0}",clam); } public String Describe() { return String.Format("fancy clam pizza with {0} and {1}",ClamType(), cheese); } } } 52 / 115 2. Registration

namespace DITest{ public class IoCInstaller: IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register(Classes .FromThisAssembly() .InNamespace("DITest.NYStyle") .WithServiceAllInterfaces()); container.Register(Classes .FromThisAssembly() .AllowMultipleMatches() .InSameNamespaceAs() .WithServiceAllInterfaces()); } } } Castle Windsor, http://www.castleproject.org 53 / 115 3. Resolution

var container = new WindsorContainer(); // adds and configures all components using WindsorInstallers from executing assembly container.Install(FromAssembly.This());

// instantiate and configure root component and all its dependencies and their dependencies and...

var p = container.Resolve(); Console.WriteLine(p.Describe()); 54 / 115

Part XI

Singleton 55 / 115 What about static methods?

public class Singleton { private static Singleton instance = new Singleton(); private String name; public String getName() { return name; } public static void someOtherMethod(){ System.out.println("Hi there!"); } private Singleton() { try { // Very expensive job indeed Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } name = Math.random() > 0.5 ? "Jonas" : "Anders"; } } Our app takes forever to load if the Singleton class is part of it. 56 / 115

// Thread that does not use the Singleton object Thread t1 = new Thread(new StaticMethodInvocation()); // Thread that uses the Singleton object Thread t2 = new Thread(new SingletonLookup()); t0 = System.nanoTime(); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } someOtherMethod invoked Singleton name: Anders Singleton lookup took 1 003 348 000 ns Static method invocation took 1 002 463 000 ns 57 / 115 How about now?

private static Singleton instance;

public static Singleton getInstance() { if (instance == null){ instance = new Singleton(); } return instance; }

I How about now? someOtherMethod invoked Singleton name: Anders Static method invocation took 899 000 ns Singleton lookup took 1 003 348 000 ns 58 / 115

What about threads? 59 / 115 private Singleton() { try { // Very expensive job indeed Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } name = Math.random() > 0.5 ? "Jonas" : "Anders"; } private static final class SingletonLookup implements Runnable { @Override public void run() { System.out.println(MessageFormat.format("Singleton name: {0} ", Singleton.getInstance().getName())); } } 60 / 115

public static void main(String[] args) { Thread t1 = new Thread(new SingletonLookup()); Thread t2 = new Thread(new SingletonLookup()); t0 = System.nanoTime(); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { // TODO Auto -generated catch block e.printStackTrace(); } System.out.println("Singleton name after our threads have run: "+Singleton.getInstance().getName()); } Singleton name: Jonas Singleton name after our threads have run: Anders Oops! 61 / 115

public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } Singleton name: Anders Singleton name: Anders Singleton lookup took 1 003 340 000 ns Singleton lookup took 1 003 286 000 ns Singleton name after our threads have run: Anders

Woohoo! 62 / 115 Singleton as Enum public enum EnumSingleton { INSTANCE; private String name; private int age;

public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 63 / 115 Singletons in Ruby 64 / 115

class A end irb(main):014:0> a # a = A.new irb(main):016:0> A.new RuntimeError: Illegal! class << A from (irb):10:in `new' def new from (irb):16 raise "Illegal!" from ruby-2.0.0-p247/bin/ end irb:13:in `

' end

Now we have one object, but we cannot produce another of the same class 65 / 115 Singleton: consequences

- Violates several design principles! + Ensures single objects per class I Saves memory I Ensures consistency 66 / 115 Singleton considered dangerous

I Encapsulate what varies I Program to an interface, not to an implementation I Favor composition over inheritance I Classes should be open for extension but closed for modification I Don’t call us, we’ll call you I Depend on abstractions, do not depend on concrete classes I Classes should only have one reason to change I Strive for loosely-coupled design 67 / 115

Part XII

Builder 68 / 115 69 / 115 70 / 115 71 / 115

Client

Director

Builder 72 / 115

Abstract Factory

Client receives a Factory Client requests a product from Factory ⇒ Client receives an abstract product

Builder

Client initializes Director with Builder Client asks Director to build Client requests product from Builder ⇒ Client receives a builder-specific product 73 / 115 Builder: consequences

+ Can control the way objects are - Not necessarily a common interface created for products + Can produce different products using - Clients must know how to initialize the same Director builders and retrieve products 74 / 115 Adapter 75 / 115

Class Adapter

Object Adapter 76 / 115 Multiple back-end objects 77 / 115 Multiple back-end methods 78 / 115

public interface Turkey { public interface Duck { public void gobble(); public void quack(); public void fly(); public void fly(); } } public class DuckAdapter implements public class TurkeyAdapter implements Turkey { Duck { Duck duck; Turkey turkey; Random rand;

public TurkeyAdapter(Turkey turkey) { public DuckAdapter(Duck duck) { this.turkey = turkey; this.duck = duck; } rand = new Random(); } public void quack() { turkey.gobble(); public void gobble() { } duck.quack(); } public void fly() { for(int i=0; i < 5; i++) { public void fly() { turkey.fly(); if (rand.nextInt(5) == 0) { } duck.fly(); } } } } } 79 / 115 Adapter: consequences

+ Isolates interface changes to the adapter class - Class adapters require target interfaces or multiple inheritance in the language 80 / 115

Part XIII

Bridge 81 / 115 Abstraction == That which we (should) care about 82 / 115 Remote / TV

Samsung LG Logitech Harmony On() Off() On() Off() One For All On() Off() On() Off() 83 / 115 Transmission type / Message type

Password recovery Signup E-mail Send() Send() SMS Send() Send() 84 / 115

Bridge Strategy Intent Decouple two class hierarchies (ab- Allow for exchangeable algorithms straction/implementation) Collaborations The Bridge forwards requests to the The Context and Strategy collabo- Implementor rate, passing data between them 85 / 115

Bridge Adapter Intent Decouple two class hierarchies (ab- Convert an existing class to fit a straction/implementation) new interface Applicability In a new system In an existing system 86 / 115 Design principles

I Encapsulate what varies I Program to an interface, not to an implementation I Favor composition over inheritance I Classes should be open for extension but closed for modification I Don’t call us, we’ll call you I Depend on abstractions, do not depend on concrete classes I Classes should only have one reason to change 87 / 115 Bridge: consequences

+ Lets two class hierarchies with common superclasses vary independently - If some implementation classes do not support an abstract concept, the abstraction breaks 88 / 115

Part XIV

Observer 89 / 115 90 / 115 91 / 115 92 / 115

Subject Concrete Observers 93 / 115 Mediator vs Observer

An Observer lets one object (or event) talk to a set of objects. A Mediator lets objects talk to each other through the Mediator. 94 / 115 Design principles

I Encapsulate what varies I Program to an interface, not to an implementation I Favor composition over inheritance I Classes should be open for extension but closed for modification I Don’t call us, we’ll call you I Depend on abstractions, do not depend on concrete classes I Classes should only have one reason to change I Strive for loosely-coupled design 95 / 115

Part XV

Chain of Responsibility 96 / 115 97 / 115 98 / 115 Examples

I Logging I Input management in GUI:s 99 / 115 CoR: consequences

+ Provides the Observer with more control over invocation of targets - A handler does not know if it will receive a message, depending on the behavior of other handlers in the chain 100 / 115 Memento 101 / 115 102 / 115

Iterative Optimizer iteration current target value current solution Optimize() SolverMemento Abort() iteration GetState() current target value SetState() current solution

Client - memento - optimizer Optimize() Abort() ResetOptimizer(SolverMemento) 103 / 115 104 / 115 Mementos in GUIs - Undo/Redo 105 / 115 Memento: consequences

+ Can externalize object state for later restoration within the lifetime of the object + Encapsulates access to the objects’ inner state - Depending on implementation, access to private fields requires memento classes as inner/friend classes to each domain class 106 / 115

Part XVI

Command 107 / 115 Command 108 / 115 Remote control 109 / 115 110 / 115 111 / 115 Command: consequences

+ Allows extensions of commands + Decouples the execution from the specification of the command - Bad design if not needed! - May be confusing if it removes the receiver from responsibilities 112 / 115

Part XVII

Finishing up 113 / 115 Template method, strategy, or factory?

I When is the algorithm chosen? Compile-time Template Run-time Strategy, factory Template Often has several methods in the class, all implemented by the pattern Strategy Usually only has one method in the class (execute or similar) Factory Is a creational pattern (returns an object) 114 / 115 Coursework

I Intro seminar I Using design patterns lab+seminar I Reading design (next week; more info to come) 115 / 115 References

Erich Gamma et al. Design Patterns: Elements of Reusable Object-oriented Software. Boston, MA, USA: Addison-Wesley Longman Publishing Co., Inc., 1995. isbn: 0-201-63361-2. Reid Smith. “Panel on Design Methodology”. In: Addendum to the Proceedings on Object-oriented Programming Systems, Languages and Applications (Addendum). OOPSLA ’87. Orlando, Florida, USA: ACM, 1987, pp. 91–95. isbn: 0-89791-266-7. doi: 10.1145/62138.62151.