CSC 480 Software Engineering Design With Patterns
The Essence of Patterns Each pattern describes a problem which occurs over and over again, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. Christopher Alexander
What Is a Design Pattern? In general, a pattern has four essential elements –The pattern name – abstracts a design problem, its solutions, and consequences (vocabulary) –The problem – explains the context and describes how to represent algorithm as objects –The solution – describes the elements that make up the design, their relationships, responsibilities, and collaborations –The consequences – the results and trade-offs of applying the pattern (evaluation)
The Catalog of GoF Patterns Design patterns are first classified by their purpose –Creational – the process of object creation –Structural – composition of classes and objects –Behavioral – the ways in which classes and objects interact and distribute responsibilities The second criterion is scope –Class – static, fixed at compile-time –Object – more dynamic, changeable at run-time
Design Pattern Space
TEMPLATE METHOD Pattern The Template Method pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
Context An algorithm is applicable for multiple types. The algorithm can be broken down into primitive operations. The primitive operations can be different for each type The order of the primitive operations doesn't depend on the type
Solution Define a superclass that has a method for the algorithm and abstract methods for the primitive operations. Implement the algorithm to call the primitive operations in the appropriate order. Do not define the primitive operations in the superclass, or define them to have appropriate default behavior. Each subclass defines the primitive operations but not the algorithm. (Methods that implement these operations are known as hook methods)
Structure templateMethod() hookMethod1() hookMethod2() GenericClass... hookMethod1()... hookMethod2()... hookMethod1() hookMethod2() ConcreteClass
Example A Generic Function Plotter func() paint() plotFunction() drawCoordinates Plotter func() PlotSine func() PlotCosine Applet Example A Generic Function Plotter Example A Generic Function Plotter (follow link to view source code)
How to Memorize? The Hollywood Principle Don’t call us, we’ll call you. When we design with the Template Method pattern, we’re telling subclasses the same thing Other patterns that make use of the Hollywood Principle –Observer –Factory method (to be discussed shortly)
Façade Pattern The façade pattern provides a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.
Context A subsystem consists of multiple classes, making it complicated for clients to use Implementor may want to change subsystem classes Want to give a coherent entry point
Solution Define a facade class that exposes all capabilities of the subsystem as methods The facade methods delegate requests to the subsystem classes The subsystem classes do not know about the facade class
Structure
Example public class Car { Engine engine; //other instance variables public Car() {... } public void start(Key key) { Doors doors = new Doors(); boolean authorized = key.turns(); if (authorized) { engine.start(); updateDashboardDisplay(); doors.lock(); } public void updateDashboardDisplay() {... } }
How to Memorize? The Principle of Least Knowledge Talk only to your immediate friends. This principle guides us to reduce the interactions between objects to just a few close “friends” –Prevent from having a large number of classes coupled together, i.e., less unnecessary dependencies –Prevent from design fragile systems that’s costly to maintain: changes in one part cascade to other parts
FACTORY METHOD Pattern The Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Context A type (the creator) creates objects of another type (the product). Subclasses of the creator type need to create different kinds of product objects. Clients do not need to know the exact type of product objects.
Solution Define a creator type that expresses the commonality of all creators. Define a product type that expresses the commonality of all products. Define a method, called the factory method, in the creator type. The factory method yields a product object. Each concrete creator class implements the factory method so that it returns an object of a concrete product class.
Structure
Example public abstract class PizzaStore { public Pizza orderPizza(String type) { Pizza pizza; pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } abstract Pizza createPizza(String type); }
Example public class NYPizzaStore { Pizza createPizza(String type) { if (type.equals”cheese”) return new NYStyleCheesePizza(); else if (type.equals”veggie”) return new NYStyleVeggiePizza(); else if (type.equals”clam”) return new NYStyleClamPizza(); else if (type.equals”pepperoni”) return new NYStylePepperoniPizza(); else return null; } }
Example public abstract class Pizza { String name; String dough; String sauce; ArrayList toppings = new ArrayList(); void prepare() { System.out.println(“Preparing ” + name); System.out.println(“Tossing dough...”); System.out.println(“Adding sauce...”); System.out.println(“Adding toppings:”); for (int i=0; i<toppings.size(); i++) System.out.println(“ ” + toppings.get(i)); } void bake() { System.out.println(“Bake for 25 minutes at 350”); } //to be continued
Example //to be continued void cut() { System.out.println(“Cutting the pizza into diagonal slices”); } void box() { System.out.println(“Place the pizza in an official PizzaStore box”); } } public class NYStyleCheesePizza extends Pizza { public NYStyleCheesePizza() { name = “NY Style Sauce and Cheese Pizza”; dough = “Thin Crust Dough”; sauce = “Marinara Sauce”; toppings.add(“Grated Reggiano Cheese”); } }