0% found this document useful (0 votes)
14 views

02 On Design Patterns

Uploaded by

arination150
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views

02 On Design Patterns

Uploaded by

arination150
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 113

1 / 113

TDDE45 - Lecture 2: Design Patterns

Adrian Pop and Martin Sjölund

Department of Computer and Information Science


Linköping University

2022-08-31
2 / 113

Part I

Intro
3 / 113

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 / 113

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 / 113

Principles + Problem = Pattern


6 / 113

Principles = SOLID + Some general tips


7 / 113

SOLID

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 / 113

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 / 113

Full instructions are on the course homepage

One of your tasks is to:


Read specifically 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).
10 / 113

Structure of the book


TheGang 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 (1997))
I Participants – classes or objects in the design pattern
I Collaborations – related to participants
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 / 113

Part III

Some Design Patterns


12 / 113

Outline

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
I Memento
Injection)
I Command
I Singleton (+ example in Ruby)
13 / 113

Part IV

Strategy
14 / 113

Strategy

Strategy
Context

Client
15 / 113

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 / 113

Part V

Factory Method
17 / 113

Factory method (before)


18 / 113

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 / 113

Factory method
20 / 113

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 / 113

Part VI

Decorator
22 / 113

Decorator

Component

Beverage b = new Coffee ();


b = new SweetenedBeverage (new SweetenedBeverage (b));

Decorator

return 5+ beverage .cost ();


23 / 113

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 / 113

Part VII

Template Method
25 / 113

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 / 113

Template method: Consequences

+ Can isolate the extensions possible to an algorithm


+ Isolates clients from algorithm changes
27 / 113

Template method
28 / 113

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 / 113

Template method?

public class Duck implements Comparable <Duck > {


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 <Duck >(){ 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 / 113

Java 8: With inline lambda (not Template method)

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


. compareTo (arg0. weight ));
31 / 113

Part VIII

Composite
32 / 113

Waiter

Diner
menu
print() printMenu()

Pizza
menu
Breakfast
menu print()

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

Dark
roast
Coffee
Tea Espresso print()
33 / 113
34 / 113

Client

Component

Composite

Leaf
35 / 113

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 / 113

Part IX

Abstract Factory
37 / 113
38 / 113
39 / 113

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
40 / 113
41 / 113
42 / 113
43 / 113

Concrete Factory

Abstract Factory

Abstract Products
44 / 113

Clients
45 / 113

Abstract factory: consequences

+ Isolates clients from concrete dependencies


+ Makes interchanging families of products easier
46 / 113

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

Design principles - Abstract Factory

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 / 113

Part X

Dependency Injection
49 / 113

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
50 / 113

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 );
}
}
51 / 113

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


52 / 113

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 ());
53 / 113

Part XI

Singleton
54 / 113

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.
55 / 113

// 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
56 / 113

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
57 / 113

What about threads?


58 / 113

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

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!
60 / 113

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!
61 / 113

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;
}
}
62 / 113

Singletons in Ruby
63 / 113

class A
end irb(main):014:0 > a
#<A:0 x007f8d6b92bcb0 >
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 `<main >'
end

Now we have one object, but we cannot produce another of the same class
64 / 113

Singleton: consequences

- Violates several design principles!


+ Ensures single objects per class
I Saves memory
I Ensures consistency
65 / 113

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
66 / 113

Part XII

Builder
67 / 113
68 / 113
69 / 113
70 / 113

Client

Director

Builder
71 / 113

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
72 / 113

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
73 / 113

Part XIII

Adapter
74 / 113

Adapter
75 / 113

Class Adapter

Object Adapter
76 / 113

Multiple back-end objects


77 / 113

Multiple back-end methods


78 / 113

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 / 113

Adapter: consequences

+ Isolates interface changes to the adapter class


- Class adapters require target interfaces or multiple inheritance in the language
80 / 113

Part XIV

Bridge
81 / 113

Abstraction == That which we (should) care about


82 / 113

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
83 / 113

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
84 / 113

Design principles - Bridge

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
85 / 113

Bridge: consequences

+ Lets two class hierarchies with common superclasses vary independently


- If some implementation classes do not support an abstract concept, the
abstraction breaks
86 / 113

Part XV

Observer
87 / 113

RSS feeds
88 / 113
89 / 113
90 / 113

Subject Concrete Observers


91 / 113

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.
92 / 113

Design principles - Observer

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
93 / 113

Part XVI

Chain of Responsibility
94 / 113
95 / 113
96 / 113

Examples

I Logging
I Input management in GUI:s
97 / 113

Chain of Responsibility: 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
98 / 113

Part XVII

Memento
99 / 113

Memento
100 / 113
101 / 113

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)
102 / 113

Mementos in GUIs - Undo/Redo


103 / 113

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
104 / 113

Part XVIII

Command
105 / 113

Command
106 / 113

Remote control
107 / 113
108 / 113
109 / 113

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
110 / 113

Part XIX

Finishing up
111 / 113

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)
112 / 113

Coursework

I Intro seminar
I Using design patterns lab (implement design in skeleton) + seminar (finished with
the lab and share solution 24h in advance)
I Design principles and Reading design patterns (next week)
113 / 113

References

[Gam+95] 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.
[Smi87] 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.

You might also like