
1 / 115 TDDE45 - Lecture 2: Design Patterns 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> { 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 / 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 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 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<IoCInstaller>() .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
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages115 Page
-
File Size-