TDDB84 Summary & wrap-up & some tips & some design patterns & some other stuff tisdag 20 oktober 15 Agenda • Course goals, expectations • Writing papers: FAQ • Design Patterns revisited • Course summary • Life after the course tisdag 20 oktober 15 Course goals Identify and explain software design principles and design patterns in existing object-oriented software. Lab 1, 2 tisdag 20 oktober 15 Course goals Apply software design principles and design patterns when working with existing object-oriented software. Lab 1, 3 tisdag 20 oktober 15 Course goals Describe the purpose and consequences of design patterns in object-oriented software. Lab 2, 3, final paper tisdag 20 oktober 15 Course goals Critically evaluate software design principles and design patterns in relationship to software qualities. Lab 3, final paper tisdag 20 oktober 15 Course goals Analyze the relationship between software design principles, design patterns, programming languages and application frameworks. Final paper tisdag 20 oktober 15 Expectations • Learn about design patterns • Learn when to use design patterns • Learn about design patterns in real software • Learn about the consequences of design patterns tisdag 20 oktober 15 Writing Papers, FAQ tisdag 20 oktober 15 Writing Papers, tips • Be • specific • precise • formal • direct • unapologetic tisdag 20 oktober 15 What is complexity? Design complexity, cyclomatic complexity? This is not a popular science text. Refrain from wording that is ambiguous or less well defined (”forgiving”, ”good”, ”bad”, ”easy”) Do not say something is ”very hard”, use a reference and be precise about what exactly that reference says Do not say you ”will” do something, or ”intends”, be direct and state what you DO, or have DONE. You do not have to state ”someone made me write this”, or ”Due to time constraints”: you will ALWAYS have external constraints on your work, as does everyone else. Write about what you have done, do not make excuses for what you have not done. Writing Papers, tips • Use • references • the style of research papers as a guide • the hourglass style • your team tisdag 20 oktober 15 Back up all claims with references Check your wording & justifications against academic publications, not previous years’ reports. Everything before the narrow part should lead to the waist, and everything after should relate to the waist. Don’t let your paper be overly focused on background material: you need to introduce only that which is necessary for someone else of approximately your own backgrounds (before the course) to understand the core of your paper: your evaluation of a specific design pattern. Please do conduct a second round of reviews Design Patterns revisited tisdag 20 oktober 15 Principles + Problem = Pattern tisdag 20 oktober 15 Principles = SOLID + Some more tips tisdag 20 oktober 15 Some more tips • Encapsulate what varies • Program to an interface not to an implementation • Favor Composition over Inheritance • Don’t call us, we’ll call you tisdag 20 oktober 15 Some more tips • Depend upon abstractions. Do not depend upon concrete classes. • Strive for loosely coupled designs between objects that interact • Only talk to your friends tisdag 20 oktober 15 Some Design Patterns tisdag 20 oktober 15 You choose! • • • • • • • tisdag 20 oktober 15 Strategy Factory Method Decorator Template Method Composite Abstract Factory (+ Dependency Injection) Singleton (+ example in Ruby) • • • • • • • Builder Adapter Bridge Observer Chain of Responsibility Memento Command Strategy tisdag 20 oktober 15 Context Client tisdag 20 oktober 15 Strategy Strategy Strategy: Consequences Can choose +implementation of a strategy at run time Eliminate hardcoded +conditionals Avoids excessive +subclassing tisdag 20 oktober 15 must be aware - Clients of different strategies - Communication required between context and strategies many - Potentially strategy objects created Factory Method tisdag 20 oktober 15 Factory method (before) tisdag 20 oktober 15 Factory method (before) tisdag 20 oktober 15 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; } Factory method tisdag 20 oktober 15 Factory method Decouples clients from +specific dependency classes Eliminates hardcoded +conditionals Connects parallel class +hierarchies (NY*Pizza, Chicago*Pizza) tisdag 20 oktober 15 keeping factory - Requires methods in sync with domain classes Decorator tisdag 20 oktober 15 Component Decorator Beverage b = new Coffee(); b = new SweetenedBeverage(new SweetenedBeverage(b)); Decorator return 5+beverage.cost(); tisdag 20 oktober 15 Decorator Dynamically adds +behavior to specific objects are - Decorator not of the same type as Customizes an abstract +class without knowing the result in many small - May objects instances of a class implementations tisdag 20 oktober 15 the objects it comprises Template Method tisdag 20 oktober 15 class Beverage { public: void prepareRecipe(); void boilWater(); void pourInCup(); }; class Coffee{ public: void prepareRecipe(); void boilWater(); void brewCoffeeGrinds(); void pourInCup(); void addSugarAndMilk(); }; tisdag 20 oktober 15 class Tea{ public: void prepareRecipe(); brew void boilWater(); void steepTeaBag(); void pourInCup(); addCondiments void addLemon(); }; Template method: Consequences Can isolate the +extensions possible to an algorithm Isolates clients from +algorithm changes tisdag 20 oktober 15 Template method tisdag 20 oktober 15 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"); } } tisdag 20 oktober 15 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); } }); Template method? 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); } } tisdag 20 oktober 15 Yes tisdag 20 oktober 15 // Java 8: With inline lambda Arrays.sort(ducks, (arg0, arg1) -> new Integer(arg1.weight).compareTo(arg0.weight)); Composite tisdag 20 oktober 15 Waiter Diner menu Pizza menu Clam Pizza tisdag 20 oktober 15 print() Breakfast menu printMenu() print() Cheese Pizza Coffee menu Ham & eggs Spam & eggs Dark roast Coffee Tea Espresso print() Eggs & spam Spam, spam & eggs print() Yes indeed we are intentionally violating the SRP. Actually I m not violating it; I m trading it for transparency tisdag 20 oktober 15 • By allowing the Component Interface to contain the child management operations and leaf operations, a client can treat both composite and leaf nodes uniformly Client Component Composite Leaf tisdag 20 oktober 15 Composite: consequences Allow us to treat +composite objects and composite - Creates classes that violate the Allows arbitrarily +complex trees composite cannot - The rely on components to individual objects uniformly tisdag 20 oktober 15 principle of a single responsibility implement all methods Abstract factory tisdag 20 oktober 15 Ingredients Pizza Store Fresh Clam Mozzarella Cheese NY Thin Crust Dough Frozen Clam Parmesan Cheese Thick Crust Dough tisdag 20 oktober 15 Clients I Want a Cheese Pizza Chicago Abstract Factory Example ! Interface toolkit to support multiple look-and-feel standards 50 tisdag 20 oktober 15 The Abstract Factory Template ! Provide an interface for creating families of related or dependent objects without specifying their concrete classes. 49 tisdag 20 oktober 15 tisdag 20 oktober 15 tisdag 20 oktober 15 tisdag 20 oktober 15 Concrete Factory Abstract Factory Abstract Products tisdag 20 oktober 15 Clients tisdag 20 oktober 15 Abstract factory: consequences Isolates clients from +concrete dependencies Makes interchanging +families of products easier tisdag 20 oktober 15 Strategy • When related classes only differ in behavior • You need different variants of an algorithm • An algorithm uses data the clients don’t need to know • A class uses conditionals for selecting behavior Behavioral tisdag 20 oktober 15 Abstract Factory • A system should be independent of how its products are created • A system should be configured with one of multiple families of products • You want to provide a class library of products, and only expose their interfaces Creational 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 modification • Don’t call us, we’ll call you tisdag 20 oktober 15 Dependency Injection tisdag 20 oktober 15 ICheesePizza -cheese StandardCheesePizza <<ICheese> > MozzarellaCheese ParmesanCheese IClamPizza -cheese -clam <<IClam>> FancyClamPizza FreshClam FrozenClam NYStyle ChicagoStyle Distinguished by namespaces in C# tisdag 20 oktober 15 DI: 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 tisdag 20 oktober 15 1. Dependencies namespace DITest { ! public class FancyClamPizza: IClamPizza ! { ! ! private IClam clam; ! ! private ICheese cheese; tisdag 20 oktober 15 ! ! ! ! ! ! ! ! ! ! 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); } 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 tisdag 20 oktober 15 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 ()); tisdag 20 oktober 15 Singleton tisdag 20 oktober 15 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() { [ ... ] } What about static methods? } 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 tisdag 20 oktober 15 Thread t1 = new Thread(new StaticMethodInvocation()); 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 tisdag 20 oktober 15 How about now? private static Singleton instance; public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } someOtherMethod invoked Static method invocation took 899 000 ns Singleton name: Anders Singleton lookup took 1 002 277 000 ns tisdag 20 oktober 15 What about threads? tisdag 20 oktober 15 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())); } } 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(); Singleton name: Anders t2.join(); Singleton name: Jonas } catch (InterruptedException e) { Singleton name after our threads have run: Anders // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Singleton name after our threads have run: "+Singleton.getInstance().getName()); } tisdag 20 oktober 15 Oops! public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } Singleton Singleton Singleton Singleton Singleton name: Anders name: Anders lookup took 1 003 340 000 ns lookup took 1 003 286 000 ns name after our threads have run: Anders Woohoo! tisdag 20 oktober 15 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; } } tisdag 20 oktober 15 Singletons in Ruby Object A MetaClass class A; end Singleton Class for foo foo tisdag 20 oktober 15 foo = A.new Class Singleton Class for A class << foo; end A class A; end class << A; end 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 /Users/olale/.rvm/rubies/ruby-2.0.0-p247/bin/irb:13:in `<main>' Now we have one object, but we cannot produce another of the same class tisdag 20 oktober 15 Singleton: consequences Ensures single objects per +class tisdag 20 oktober 15 several design - Violates principles! • • • • tisdag 20 oktober 15 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 modification • • Don’t call us, we’ll call you • • Classes should only have one reason to change Depend on abstractions, do not depend on concrete classes Strive for loosely-coupled design Builder tisdag 20 oktober 15 Builder – Non Software Exam TDDB82 Design Patterns HT1 2009 LECTURE 05 tisdag 20 oktober 15 Client Director build() Builder buildA() buildB() buildC() getProduct() tisdag 20 oktober 15 The Builder Separa of a com represe same c can cre represe The client creates t configures it with t Director notifies th of the product shou tisdag 20 oktober 15 Builder handles req and adds parts to t The client retrieves builder. Client Director Builder tisdag 20 oktober 15 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 tisdag 20 oktober 15 Client receives a builder-specific product Builder: consequences Can control the way +objects are created Can produce different +products using the same Director tisdag 20 oktober 15 necessarily a - Not common interface for products must know how - Clients to initialize builders and retrieve products Adapter tisdag 20 oktober 15 Class Adapter Object Adapter ! An object adapter relies on object composition 11 Object Adapter tisdag 20 oktober 15 12 Multiple back-end objects Client Target do() Adapter -adaptee1 -adaptee2 do() tisdag 20 oktober 15 Adaptee1 +perform() Adaptee2 +perform() Multiple back-end methods Client Target do() Adapter -adaptee do() adaptee.foo() adaptee.bar() tisdag 20 oktober 15 Adaptee1 +foo() +bar() public interface Turkey { public void gobble(); public void fly(); } 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(); } } tisdag 20 oktober 15 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) duck.fly(); } } == 0) { Adapter: consequences interface changes +toIsolates the adapter class tisdag 20 oktober 15 adapters require - Class target interfaces or multiple inheritance in the language Bridge tisdag 20 oktober 15 The Bridge Pattern Structure Abstraction == That which we (should) care about 20 tisdag 20 oktober 15 TV Samsung LG Logitech Harmony On() Off() On() Off() One For All On() Off() On() Off() Remote tisdag 20 oktober 15 Message type Transmission type tisdag 20 oktober 15 Password recovery Signup E-mail Send() Send() SMS Send() Send() Intent Collaborations tisdag 20 oktober 15 Bridge Strategy Decouple two class hierarchies (abstraction/ implementation) Allow for exchangeable algorithms The Context and The Bridge forwards Strategy requests to the collaborate, passing Implementor data between them Bridge Intent Applicability tisdag 20 oktober 15 Adapter Decouple two class Convert an existing hierarchies class to fit a new (abstraction/ interface implementation) In a new system In an existing system Design principles tisdag 20 oktober 15 • • • • Encapsulate what varies • • Don’t call us, we’ll call you • Classes should only have one reason to change Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Depend on abstractions, do not depend on concrete classes Bridge: consequences Lets two class hierarchies +with common superclasses vary independently tisdag 20 oktober 15 some implementation - Ifclasses do not support an abstract concept, the abstraction breaks Observer tisdag 20 oktober 15 tisdag 20 oktober 15 Weather Station Humidity Display subscribe() subscribe() publish() publish() unsubscribe() publish() tisdag 20 oktober 15 Average Temp Display ! The only things the subject knows ab that it implements a certain interface tisdag 20 oktober 15 ! We can add new observers at any tim ! We never need to modify the subject t observers ! We can reuse subjects or observers in other ! Changes to either the subject or an ob the other Subject tisdag 20 oktober 15 Concrete Observer Mediator vs Observer tisdag 20 oktober 15 Design principles tisdag 20 oktober 15 • • • • Encapsulate what varies • • Don’t call us, we’ll call you • • Classes should only have one reason to change Program to an interface, not to an implementation Favor composition over inheritance Classes should be open for extension but closed for modification Depend on abstractions, do not depend on concrete classes Strive for loosely-coupled design Chain of Responsibility tisdag 20 oktober 15 SPAM Filter isSpam(Message) accept Size Filter isTooLarge(Message) accept Sorting Filter sort(Message) process reject Message arrived reject Message rejected tisdag 20 oktober 15 Chain of Respon tisdag 20 oktober 15 Avoid coupling the sender of a request to its rec more than one object a chance to handle the re receiving objects and pass the request along th object handles it. Examples • Logging • Input management in GUI:s tisdag 20 oktober 15 CoR: consequences provides the Observer +with more control over invocation of targets tisdag 20 oktober 15 handler does not - Aknow if it will receive a message, depending on the behavior of other handlers in the chain Memento tisdag 20 oktober 15 The Memento – Non So The Me extern interna can be later. ! ! tisdag 20 oktober 15 ! This pattern is common among do-it-yourself mechanics repairin their cars. The drums are removed from both sides, exposing bot brakes . Only one side is disassembled, and the other side serves as a Me brake parts fit together Only after the job has been completed on one side is the other si When the second side is disassembled, the first side acts as the TDDB84 Design Patterns Slide 3 Iterative Optimizer iteration current target value current solution Optimize() Abort() GetState() SetState() SolverMemento iteration current target value current solution Client - memento - optimizer Optimize() Abort() ResetOptimizer(SolverMemento) tisdag 20 oktober 15 Memento Originator o = new Originator(); o.state = "On"; // Store internal state Caretaker c = new Caretaker(); c.memento = o.CreateMemento(); // Continue changing originator o.State = "Off"; // Restore saved state o.SetMemento( c.Memento ); TDDB84 Design Patterns Slide 4 tisdag 20 oktober 15 Mementos in GUI:s Undo/Redo User 1 gi User 2 gi jo User 4 tisdag 20 oktober 15 gi Name Age Ginnie 24 Name Age Ginnie 24 Johnny 37 Name Age Ginnie 24 3 Undo Redo Cut Copy Paste Paste special... Delete Select All Memento: consequences Can externalize object +state for later restoration within the lifetime of the object Encapsulates access to the +objects’ inner state tisdag 20 oktober 15 on - Depending implementation, access to private fields requires memento classes as inner/friend classes to each domain class Command tisdag 20 oktober 15 Command Client Waiter Order Chef Order Place Order Cook tisdag 20 oktober 15 Remote control The Ultimate Remote Control Fan High() Low() Off() GetSpeed() Joe’s Ultimate Remote Control On Off On Off On Off On Off On Off On Off On Off Undo Lamp On() Off() Dim() TV TurnOn() TurnOff() SetChannel() tisdag 20 oktober 15 TDDB84 Design Patterns Slide 30 Client Invoker -command perform() Receiver +perform() tisdag 20 oktober 15 Command +execute() Concrete Command -receiver Client Concrete Commands Invoker Receiver Command tisdag 20 oktober 15 Command: consequences Allows extensions of +commands design if not - Bad needed! Decouples the execution +from the specification of be confusing if it - May removes the receiver the command tisdag 20 oktober 15 from responsibilities Course summary • Practical work: • Intro seminar + three labs • Reflection and analysis: • Reading a research paper, and studying design patterns in a real context tisdag 20 oktober 15 Life after the course • Writing your papers :) • Masters theses: Info @ 12:15! • Research project in Software Engineering • Exam? No. tisdag 20 oktober 15 Thanks for your participation, and good luck with your papers! tisdag 20 oktober 15