TDDE45 - Lecture 2: Design Patterns Martin Sjlund Department of - - PowerPoint PPT Presentation

tdde45 lecture 2 design patterns
SMART_READER_LITE
LIVE PREVIEW

TDDE45 - Lecture 2: Design Patterns Martin Sjlund Department of - - PowerPoint PPT Presentation

1 / 115 TDDE45 - Lecture 2: Design Patterns Martin Sjlund Department of Computer and Information Science Linkping University 2020-08-11 2 / 115 Part I Intro 3 / 115 Brief History (1) General concept of patterns (253 of them, for


slide-1
SLIDE 1

1 / 115

TDDE45 - Lecture 2: Design Patterns

Martin Sjölund

Department of Computer and Information Science Linköping University

2020-08-11

slide-2
SLIDE 2

2 / 115

Part I Intro

slide-3
SLIDE 3

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.

slide-4
SLIDE 4

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 16

slide-5
SLIDE 5

5 / 115

Principles + Problem = Pattern

slide-6
SLIDE 6

6 / 115

Principles = SOLID + Some general tips

slide-7
SLIDE 7

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)
slide-8
SLIDE 8

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 fjne), static methods (thread-safe code).
  • 9. Simple, readable code is often favorable over strictly adhering to the design

principles.

slide-9
SLIDE 9

9 / 115

Full instructions are on the course homepage

One of your tasks is to: Read specifjcally the Intent, Motivation, Applicability and Structure of 4 design patterns per person in the Gang of Four course book (or the corresponding parts in another source such as Head First Design Patterns).

slide-10
SLIDE 10

10 / 115

Structure of the book

The Gang of Four book is very structured; the following is a summary of section 1.3: ◮ Pattern name and classifjcation (creational, structural, behavioral; class or object) ◮ Intent ◮ Also known as ◮ Motivation ◮ Applicability – what poor designs can this pattern solve? ◮ Structure – graphical representation (using OMT – a predecessor to UML) ◮ Participants – classes or objects in the design pattern ◮ Collaborations – related to partcipants ◮ Consequences – trade-ofgs? ◮ Implementation – pitfalls, hints? ◮ Sample code (C++ or smalltalk) ◮ Known uses (from real code; you could of course list Eclipse on every design pattern) ◮ Related patterns – many patterns do similar things; how do they difger? Which design patterns can you combine with it?

slide-11
SLIDE 11

11 / 115

Part III Some Design Patterns

slide-12
SLIDE 12

12 / 115

You choose!

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

slide-13
SLIDE 13

13 / 115

Part IV Strategy

slide-14
SLIDE 14

14 / 115

Strategy

Context Strategy Client

slide-15
SLIDE 15

15 / 115

Strategy: Consequences

+ Can choose implementation of a strategy at run time + Eliminate hardcoded conditionals + Avoids excessive subclassing

  • Clients must be aware of difgerent

strategies

  • Communication required between

context and strategies

  • Potentially many strategy objects

created

slide-16
SLIDE 16

16 / 115

Part V Factory Method

slide-17
SLIDE 17

17 / 115

Factory method (before)

slide-18
SLIDE 18

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; }

slide-19
SLIDE 19

19 / 115

Factory method

slide-20
SLIDE 20

20 / 115

Factory method

+ Decouples clients from specifjc dependency classes + Eliminates hardcoded conditionals + Connects parallel class hierarchies (NY*Pizza, Chicago*Pizza)

  • Requires keeping factory methods in

sync with domain classes

slide-21
SLIDE 21

21 / 115

Part VI Decorator

slide-22
SLIDE 22

22 / 115

Decorator

Beverage b = new Coffee(); b = new SweetenedBeverage(new SweetenedBeverage(b)); return 5+beverage.cost();

Component Decorator

slide-23
SLIDE 23

23 / 115

Decorator

+ Dynamically adds behavior to specifjc instances of a class + Customizes an abstract class without knowing the implementations

  • Decorator objects are not of the same

type as the objects it comprises

  • May result in many small objects
slide-24
SLIDE 24

24 / 115

Part VII Template Method

slide-25
SLIDE 25

25 / 115

Template Method

class Coffee{ public: void prepareRecipe(); void boilWater(); void brewCoffeeGrinds(); void pourInCup(); void addSugarAndMilk(); }; class Tea{ public: void prepareRecipe(); void boilWater(); void steepTeaBag(); void pourInCup(); void addLemon(); };

class Beverage { public: void prepareRecipe(); void boilWater(); void pourInCup(); // No brew==steep // No addCondiments };

slide-26
SLIDE 26

26 / 115

Template method: Consequences

+ Can isolate the extensions possible to an algorithm + Isolates clients from algorithm changes

slide-27
SLIDE 27

27 / 115

Template method

slide-28
SLIDE 28

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"); } }

slide-29
SLIDE 29

29 / 115

Template method?

Duck[] ducks = { new Duck("Daffy", 8), new Duck("Dewey", 2), new Duck("Howard", 7), new Duck("Louie", 2), new Duck("Donald", 10), new Duck("Huey", 2) }; Arrays.sort(ducks, new Comparator<Duck>(){ @Override public int compare(Duck arg0, Duck arg1) { return new Integer(arg1.weight).compareTo(arg0. weight); } });

No

public class Duck implements Comparable<Duck> { String name; int weight; public Duck(String name, int weight) { this.name = name; this.weight = weight; } public String toString() { return MessageFormat.format("{0} weighs {1}", name, weight); } public int compareTo(Duck object) { return new Integer(this.weight).compareTo(object .weight); } }

Yes

slide-30
SLIDE 30

30 / 115

Java 8: With inline lambda (not Template method)

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

slide-31
SLIDE 31

31 / 115

Part VIII Composite

slide-32
SLIDE 32

32 / 115

Breakfast menu Coffee menu Ham & eggs Spam & eggs Eggs & spam Spam, spam & eggs Coffee menu Dark roast Coffee T ea Espresso Pizza menu Coffee menu Clam Pizza Cheese Pizza Diner menu

Waiter

printMenu() print() print() print() print()

slide-33
SLIDE 33

33 / 115

slide-34
SLIDE 34

34 / 115

Client Component Composite Leaf

slide-35
SLIDE 35

35 / 115

Composite: consequences

+ Allow us to treat composite objects and individual objects uniformly + Allows arbitrarily complex trees

  • Creates composite classes that violate

the principle of a single responsibility

  • The composite cannot rely on

components to implement all methods

slide-36
SLIDE 36

36 / 115

Part IX Abstract factory

slide-37
SLIDE 37

37 / 115

NY Chicago

Fresh Clam Mozzarella Cheese Thin Crust Dough Frozen Clam Parmesan Cheese Thick Crust Dough

Ingredients Pizza Store Clients

I Want a Cheese Pizza

slide-38
SLIDE 38

38 / 115

slide-39
SLIDE 39

39 / 115

slide-40
SLIDE 40

40 / 115

slide-41
SLIDE 41

41 / 115

slide-42
SLIDE 42

42 / 115

slide-43
SLIDE 43

43 / 115

Abstract Products Abstract Factory Concrete Factory

slide-44
SLIDE 44

44 / 115

Clients

slide-45
SLIDE 45

45 / 115

Abstract factory: consequences

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

slide-46
SLIDE 46

46 / 115

Strategy – behavioural ◮ When related classes only difger in behaviour ◮ You need difgerent variants of an algorithm ◮ An algorithm uses data the clients don’t need to know ◮ A class uses conditionals for selecting behavior Abstract factory – creational ◮ A system should be independent of how its products are created ◮ A system should be confjgured with

  • ne of multiple families of products

◮ You want to provide a class library of products, and only expose their interfaces

slide-47
SLIDE 47

47 / 115

Design principles

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

slide-48
SLIDE 48

48 / 115

Part X Dependency Injection

slide-49
SLIDE 49

49 / 115

slide-50
SLIDE 50

50 / 115

Dependency injection: 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
slide-51
SLIDE 51

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); } } }

slide-52
SLIDE 52

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 <IoCInstaller >() .WithServiceAllInterfaces()); } } }

Castle Windsor, http://www.castleproject.org

slide-53
SLIDE 53

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 <ICheesePizza >(); Console.WriteLine(p.Describe());

slide-54
SLIDE 54

54 / 115

Part XI Singleton

slide-55
SLIDE 55

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.

slide-56
SLIDE 56

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

slide-57
SLIDE 57

57 / 115

How about now?

private static Singleton instance; public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } ◮ How about now? someOtherMethod invoked Singleton name: Anders Static method invocation took 899 000 ns Singleton lookup took 1 003 348 000 ns

slide-58
SLIDE 58

58 / 115

What about threads?

slide-59
SLIDE 59

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())); } }

slide-60
SLIDE 60

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!

slide-61
SLIDE 61

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!

slide-62
SLIDE 62

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; } }

slide-63
SLIDE 63

63 / 115

Singletons in Ruby

slide-64
SLIDE 64

64 / 115

class A end a = A.new class << A def new raise "Illegal!" end end irb(main):014:0> a #<A:0x007f8d6b92bcb0 > irb(main):016:0> A.new RuntimeError: Illegal! from (irb):10:in `new' from (irb):16 from ruby-2.0.0-p247/bin/ irb:13:in `<main>' Now we have one object, but we cannot produce another of the same class

slide-65
SLIDE 65

65 / 115

Singleton: consequences

  • Violates several design principles!

+ Ensures single objects per class

◮ Saves memory ◮ Ensures consistency

slide-66
SLIDE 66

66 / 115

Singleton considered dangerous

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

slide-67
SLIDE 67

67 / 115

Part XII Builder

slide-68
SLIDE 68

68 / 115

slide-69
SLIDE 69

69 / 115

slide-70
SLIDE 70

70 / 115

slide-71
SLIDE 71

71 / 115

Director Builder Client

slide-72
SLIDE 72

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-specifjc product

slide-73
SLIDE 73

73 / 115

Builder: consequences

+ Can control the way objects are created + Can produce difgerent products using the same Director

  • Not necessarily a common interface

for products

  • Clients must know how to initialize

builders and retrieve products

slide-74
SLIDE 74

74 / 115

Adapter

slide-75
SLIDE 75

75 / 115

Class Adapter Object Adapter

slide-76
SLIDE 76

76 / 115

Multiple back-end objects

slide-77
SLIDE 77

77 / 115

Multiple back-end methods

slide-78
SLIDE 78

78 / 115

public interface Duck { public void quack(); public void fly(); } public class TurkeyAdapter implements Duck { Turkey turkey; public TurkeyAdapter(Turkey turkey) { this.turkey = turkey; } public void quack() { turkey.gobble(); } public void fly() { for(int i=0; i < 5; i++) { turkey.fly(); } } } public interface Turkey { public void gobble(); public void fly(); } public class DuckAdapter implements Turkey { Duck duck; Random rand; public DuckAdapter(Duck duck) { this.duck = duck; rand = new Random(); } public void gobble() { duck.quack(); } public void fly() { if (rand.nextInt(5) == 0) { duck.fly(); } } }

slide-79
SLIDE 79

79 / 115

Adapter: consequences

+ Isolates interface changes to the adapter class

  • Class adapters require target interfaces or multiple inheritance in the language
slide-80
SLIDE 80

80 / 115

Part XIII Bridge

slide-81
SLIDE 81

81 / 115

Abstraction == That which we (should) care about

slide-82
SLIDE 82

82 / 115

Remote / TV

Samsung LG Logitech Harmony On() Ofg() On() Ofg() One For All On() Ofg() On() Ofg()

slide-83
SLIDE 83

83 / 115

Transmission type / Message type

Password recovery Signup E-mail Send() Send() SMS Send() Send()

slide-84
SLIDE 84

84 / 115

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

slide-85
SLIDE 85

85 / 115

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

slide-86
SLIDE 86

86 / 115

Design principles

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

slide-87
SLIDE 87

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

slide-88
SLIDE 88

88 / 115

Part XIV Observer

slide-89
SLIDE 89

89 / 115

slide-90
SLIDE 90

90 / 115

slide-91
SLIDE 91

91 / 115

slide-92
SLIDE 92

92 / 115

Subject Concrete Observers

slide-93
SLIDE 93

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.

slide-94
SLIDE 94

94 / 115

Design principles

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

slide-95
SLIDE 95

95 / 115

Part XV Chain of Responsibility

slide-96
SLIDE 96

96 / 115

slide-97
SLIDE 97

97 / 115

slide-98
SLIDE 98

98 / 115

Examples

◮ Logging ◮ Input management in GUI:s

slide-99
SLIDE 99

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
  • ther handlers in the chain
slide-100
SLIDE 100

100 / 115

Memento

slide-101
SLIDE 101

101 / 115

slide-102
SLIDE 102

102 / 115

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

  • memento
  • optimizer

Client iteration current target value current solution SolverMemento

slide-103
SLIDE 103

103 / 115

slide-104
SLIDE 104

104 / 115

Mementos in GUIs - Undo/Redo

slide-105
SLIDE 105

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 fjelds requires memento classes

as inner/friend classes to each domain class

slide-106
SLIDE 106

106 / 115

Part XVI Command

slide-107
SLIDE 107

107 / 115

Command

slide-108
SLIDE 108

108 / 115

Remote control

slide-109
SLIDE 109

109 / 115

slide-110
SLIDE 110

110 / 115

slide-111
SLIDE 111

111 / 115

Command: consequences

+ Allows extensions of commands + Decouples the execution from the specifjcation of the command

  • Bad design if not needed!
  • May be confusing if it removes the receiver from responsibilities
slide-112
SLIDE 112

112 / 115

Part XVII Finishing up

slide-113
SLIDE 113

113 / 115

Template method, strategy, or factory?

◮ 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)

slide-114
SLIDE 114

114 / 115

Coursework

◮ Intro seminar ◮ Using design patterns lab+seminar ◮ Reading design (next week; more info to come)

slide-115
SLIDE 115

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.