/** Patterns by Sandeep Desai http://www.thedesai.net email: s_desai@hotmail.com This document is a java program that contains examples of Patterns Book Reference: Head First Design Patterns by Eric Freeman, Elisabeth Freeman Design Patterns: Elements of reusable Object Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides Websites: The Portland Patterns Repository http://c2.com/cgi/wiki?WelcomeVisitors Hillside Group: http://hillside.net/ A Pattern is a solution to a problem in a context (Context is a recurring situation) (Problem is the set of constraints) Patterns give you general solutions to design problems Patterns make it easier to handle application changes An Anti Pattern tells you how to go from a problem to a BAD solution One way to group patterns Creational Patterns involve object instantiation and all provide a way to decouple a client from the objects it needs to instantiate e.g Factory Method, Abstract Factory, Singleton, Prototype, Builder Behavioural Pattern is concerned with how classes and objects interact and distribute responsibility e.g Strategy, Observer, Template Method, Command, Iterator, State, Visitor, Mediator, Interpreter, Chain of Responsibility, Memento Structural Patterns let you compose classes or objects into larger structures e.g Decorator, Proxy, Facade, Composite, Adapter, Flyweight, Bridge Another grouping is Class patterns describe how relationships between classes are defined via inheritance Relationships in class patterns are established at compile time e.g Tempalte Method, Factory Method, Adapter, Interpreter Object Patterns describe relationships between objects and are primarily defined by composition. Realtionships in object pattersn are typically create at runtime and are more dynamic and flexible Pattern Catalog contains list of patterns Formal Pattern description, define following when creating a new pattern Pattern name Intent (Short Description) Motivation (Detailted description) Applicability Structure (Diagram) Participants (lists the classes used) Collaborations (how the classes work together) Consequences (Good and Bad of usage) Implementation/Sample Code Known Uses Related Patterns OO Principles Separation of concerns, do not have class to do many misc things Cohesion, degree to which class designed for one purpose Encapsulate what varies Favor composition over inheritance Program to interface not implementation Classes should be open for extension but closed for modification Depend on abstractions. Do not depend upon concrete classes Principle of least knowledge (demeter) Talk only to your immediate friends (Loose coupling) A class hould have only one reason to change */ import java.io.*; import java.util.*; import java.lang.reflect.*; /****************************** Strategy Pattern start ************************ Strategy pattern defins a family of algorithms, encapsulates each one and makes them interchangeable. Strategy lets the algorithm vary independantly from clients that use it Alternative to inheritance In example below putting the fly method in a Duck will lead to class explosion */ interface FlyBehavior { public void fly(); } interface QuackBehavior { public void quack(); } abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { } abstract void display(); public void setFlyBehavior(FlyBehavior fb) { flyBehavior = fb; } public void setQuackBehavior(QuackBehavior qb) { quackBehavior = qb; } public void performFly() { flyBehavior.fly(); } public void performQuack() { quackBehavior.quack(); } } class FlyWithWings implements FlyBehavior { public void fly() { System.out.println("I'm flying!!"); } } class FlyNoWay implements FlyBehavior { public void fly() { System.out.println("I can't fly"); } } class Quack implements QuackBehavior { public void quack() { System.out.println("Quack"); } } class Squeak implements QuackBehavior { public void quack() { System.out.println("Squeak"); } } class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display() { System.out.println("I'm a real Mallard duck"); } } class RubberDuck extends Duck { public RubberDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new Squeak(); } public void display() { System.out.println("I'm a rubber duckie"); } } class StrategyPattern { public static void run() { MallardDuck md = new MallardDuck(); RubberDuck rd = new RubberDuck(); System.out.println("**** Strategy Pattern *****"); md.display(); md.performFly(); rd.display(); rd.performFly(); } } /***************************** Strategy Pattern end ************************/ /***************************** Observer Pattern start ************************ Publisher/Subject */ interface Observable { public void add(Observable o); public void remove(Observable o); } interface Observer { public void update(Observable o, Object args); } class StockData { String ticker; int price; } class Brokerage extends java.util.Observable { public void setStockPrice(String ticker, int price) { StockData stock = new StockData(); stock.price = price; stock.ticker = ticker; setChanged(); notifyObservers(stock); } } class Investor implements java.util.Observer { public void update(java.util.Observable o, Object args) { StockData sd = (StockData)args; System.out.println("notified=>" + sd.ticker + "=" + sd.price); } } class ObserverPattern { public static void run() { Brokerage b = new Brokerage(); Investor i = new Investor(); b.addObserver(i); System.out.println("*** Observer pattern ***"); b.setStockPrice("ORCL", 15); } } /**************************** Observer pattern end ************************/ /**************************** Decorator pattern start ************************ Decorator - Attach additional responsibilites to an object dynamically Decoration provides a flexible alternative to subclassing for extending functionality Implement wrappers e.g Java File API in java.io.* +---InputStream (abstract) | +---FileInputStream +---StringBufferInputStream +---ByteArrayInputStream +---FilterInputStream (abstract) | +---PushBackInputStream (Wrapper) +---BufferedInputStream +---DataInputStream +---LineNumberInputStream */ class LowerCaseInputStream extends FilterInputStream { public LowerCaseInputStream(InputStream in) { super(in); } public int read() throws IOException { int c = super.read(); return (c == -1 ? c : Character.toLowerCase((char)c)); } public int read(byte[] b, int offset, int len) throws IOException { int result = super.read(b, offset, len); for (int i = offset; i < offset + result; i++) { b[i] = (byte)Character.toLowerCase((char)b[i]); } return result; } } class DecoratorPattern { public static void run() { int c; System.out.println("*** Decorator pattern ***"); try { PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("test.txt"))); ps.print("HELLO\nWORLD\n"); ps.close(); InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt"))); while ((c = in.read()) >= 0) { System.out.print((char)c); } in.close(); } catch (IOException e) { e.printStackTrace(); } } } /**************************** Decorator pattern end ************************/ /**************************** Factory pattern start ************************ The Factory Method Pattern defins an interface for creating an object, but lets subclass decide which class to instantiate. Factory method lets a class defer instantiation to subclass */ abstract class ProductA { public void ship() { System.out.println("shipping product"); } } abstract class ProductB { } // Replace String type with implementation specific way of creating products interface Creator { ProductA factoryMethod(String type); } class ConcreteProductA1 extends ProductA { } class ConcreteProductA2 extends ProductA { } class ConcreteProductB extends ProductB { } class ConcreteCreator implements Creator { public ProductA factoryMethod(String type) { return new ConcreteProductA1(); } } /** The Abstract Factory Patterns provides an interface for creating families of related or dependant objects without specifying their concrete classes */ interface AbstractFactory { ProductA createProductA(String type); ProductB createProductB(String type); } class ConcreteFactory1 { ProductA createProductA(String type) { if (type.equals("A1")) return new ConcreteProductA1(); if (type.equals("A2")) return new ConcreteProductA2(); return null; } ProductB createProductB(String type) { return new ConcreteProductB(); } } class FactoryPattern { public static void run() { ConcreteFactory1 factory1 = new ConcreteFactory1(); ProductA productA = factory1.createProductA("A1"); System.out.println("*** Factory pattern ***"); productA.ship(); } } /**************************** Factory pattern end ************************/ /**************************** Singleton pattern start ************************ The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it java.lang.Runtime example of Singleton */ class Singleton { private static Singleton uniqueInstance; private Singleton() { } // prevents creation by other classes // remove synchronized if you do not want thread safe and fast performance public static synchronized Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } } class SingletonPattern { public static void run() { System.out.println("*** Singleton pattern ***"); Singleton s = Singleton.getInstance(); } } /**************************** Singleton pattern end ************************/ /**************************** Command pattern start ************************ Command - Encapsulate a request as an object, therby letting you parameterize client with different requests, queue or log request and support undoable operations e.g usage is Web Server that schedules HTTP requests as a pool of threads we can also use this to implement a persistent transaction system where we write commands requests to disk and execute them one by one, when we crash we can recover from the persistent storage */ interface Command { public void execute(); // execute request public void undo(); } class MacroCommand implements Command { Command[] commands; public MacroCommand(Command[] commands) { this.commands = commands; } public void execute() { for (int i = 0; i < commands.length; i++) { commands[i].execute(); } } public void undo() { for (int i = 0; i < commands.length; i++) { commands[i].undo(); } } } class Light { String name; public Light(String name) { this.name = name; } public void on() { System.out.println(name + " Light is on"); } public void off() { System.out.println(name + " Light is off"); } } class LightOffCommand implements Command { Light light; public LightOffCommand(Light light) { this.light = light; } public void execute() { light.off(); } public void undo() { light.on(); } } class LightOnCommand implements Command { Light light; public LightOnCommand(Light light) { this.light = light; } public void execute() { light.on(); } public void undo() { light.off(); } } class GarageDoor { public GarageDoor() { } public void up() { System.out.println("Garage Door is Open"); } public void down() { System.out.println("Garage Door is Closed"); } } class GarageDoorOpenCommand implements Command { GarageDoor garageDoor; public GarageDoorOpenCommand(GarageDoor garageDoor) { this.garageDoor = garageDoor; } public void execute() { garageDoor.up(); } public void undo() { garageDoor.down(); } } // Client/Invoker class SimpleRemoteControl { Command[] slot = new Command[3]; public SimpleRemoteControl() { } public void setCommand(int i, Command command) { slot[i] = command; } public void buttonWasPressed(int i) { slot[i].execute(); } public void undo(int i) { slot[i].undo(); } } class CommandPattern { public static void run() { System.out.println("*** Command pattern ***"); SimpleRemoteControl remote = new SimpleRemoteControl(); Light kitchenLight = new Light("Kitchen Light"); Light bedroomLight = new Light("Bedroom Light"); remote.setCommand(0, new LightOnCommand(kitchenLight)); remote.setCommand(1, new LightOnCommand(bedroomLight)); GarageDoor garageDoor = new GarageDoor(); remote.setCommand(2, new GarageDoorOpenCommand(garageDoor)); remote.buttonWasPressed(2); remote.undo(2); } } /**************************** Command pattern end ************************/ /**************************** Adapter and Facade pattern start ************************ The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces Class Adapter uses multiple inheritance which is not supported by Java Decorator Pattern adds behavior, Adapter converts behaviour Facade Patterns simplifies behaviour */ interface // Object Adapter Pattern Target { public void request(); } class Adaptee { public void specificRequest() { } } // Adapter can adapt more than one Target class Adapter implements Target { Adaptee a; public Adapter(Adaptee a) { this.a = a; } public void request() { a.specificRequest(); // convert request to Adaptee request } } class Client { public static void run() { Adaptee a = new Adaptee(); Adapter adapter = new Adapter(a); adapter.request(); // We made the Adaptee behave like Target } } class EnumerationIterator implements Iterator { Enumeration enumeration; public EnumerationIterator(Enumeration enumeration) { this.enumeration = enumeration; } public boolean hasNext() { return enumeration.hasMoreElements(); } public Object next() { return enumeration.nextElement(); } public void remove() { throw new UnsupportedOperationException(); } } class AdapterPattern { public static void run() { String[] s = { "hello", "world" }; Vector v = new Vector(Arrays.asList(s)); Iterator iterator = new EnumerationIterator(v.elements()); System.out.println("*** Adapter pattern ***"); while (iterator.hasNext()) { System.out.println(iterator.next()); } } } /** The Facade Pattern povides a unified interface to a set of interfaces in a subsystem Facade defines a higher-level interface that makes the subsystem easier to use */ class A { } class B { } class C { } // Simplify access to A, B, C etc class Facade { } /**************************** Adapter and Facade pattern end ************************/ /**************************** Template Method pattern start ************************ The Template Method Pattern defines the skeleton of an algortihm in a method, deferring some steps to subclasses. Template Method lets subclases redefine certain steps of an algorithm without changing the algorithm's structure e.g java.util.Arrays.binarySearch(Object[] a, Object key, Comparator c) Strategy allows interchangeable algorithms Template defines outline of algorithm */ abstract class Algorithm { public final void templateMethod() { step1(); if (hook()) step2(); step3(); } public void step1() { System.out.println("Step 1"); } public final void step2() { System.out.println("Step 2"); } // can't override this step public abstract void step3(); public boolean hook() { return false; } // hook with default implementation } class OverrideAlgorithm extends Algorithm { public void step1() { System.out.println("Step 1 override"); } // override public void step3() { System.out.println("Step 3"); } public boolean hook() { return true; } // hook with default implementation } class TemplateMethodPattern { public static void run() { System.out.println("*** Template Method pattern ***"); OverrideAlgorithm a = new OverrideAlgorithm(); a.templateMethod(); } } /**************************** Template Method pattern end ************************ /**************************** Iterator and Composite pattern start ************************ Iterator provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation */ class Item { private String name; public Item(String name) { this.name = name; } public String getName() { return name; } } class MyCollection { Item[] items = new Item[2]; public void add(int i, String name) { items[i] = new Item(name); } public Iterator iterator() { return new MyCollectionIterator(items); } } class MyCollectionIterator implements Iterator { Item[] items; int index = 0; public MyCollectionIterator(Item[] items) { this.items = items; } public Object next() { Item item = items[index++]; return item; } public boolean hasNext() { if (index >= items.length || items[index] == null) return false; else return true; } public void remove() { throw new UnsupportedOperationException(); } } class IteratorPattern { public static void run() { System.out.println("*** Iterator pattern ***"); MyCollection fruits = new MyCollection(); fruits.add(0, "Apple"); fruits.add(1, "Orange"); for (Iterator it = fruits.iterator(); it.hasNext(); ) { Item item = (Item)it.next(); System.out.println(item.getName()); } } } /** Composite - compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treate individual objects and compositions of objects uniformly */ abstract class Component { public abstract String getName(); public abstract void print(); public void add(Component c) { throw new UnsupportedOperationException(); } public void remove(Component c) { throw new UnsupportedOperationException(); } } class Leaf extends Component { private String name; public Leaf(String name) { this.name = name; } public void print() { System.out.println("Leaf=>" + name); } public String getName() { return name; } } class Composite extends Component { ArrayList components = new ArrayList(); private String name; public Composite(String name) { this.name = name; } public String getName() { return name; } public void print() { // recursive print System.out.println("Composite=>" + name); for (Iterator it = components.iterator(); it.hasNext(); ) { Component c = (Component)it.next(); c.print(); } } public void operation() { } public void add(Component c) { components.add(c); } public void remove(Component c) { components.remove(c); } public Component getChild(int i) { return (Component)components.get(i); } public Iterator iterator() { return components.iterator(); } } class CompositePattern { public static void run() { System.out.println("*** Composite pattern ***"); Composite foodComposite = new Composite("Food"); Composite fruitComposite = new Composite("Fruits"); fruitComposite.add(new Leaf("Apple")); fruitComposite.add(new Leaf("Orange")); foodComposite.add(fruitComposite); foodComposite.add(new Leaf("Carrot")); foodComposite.print(); } } class IteratorAndCompositePattern { public static void run() { IteratorPattern.run(); CompositePattern.run(); } } /** We can create a Collection Food that contains a Fruit Colleciton and Vegetable Collection. The class to handle both would be a composite Pattern */ /**************************** Iterator and Composite pattern end ************************/ /**************************** State pattern start ************************ The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to changes its class Reduces the if statements required */ interface State { public void operation1(); public void operation2(); public void operation3(); public void print(); } class Context { State1 state1 = new State1(this); State2 state2 = new State2(this); State currentState = state1; public void setState(State state) { currentState = state; currentState.print(); } public State getState() { return currentState; } public void operation1() { currentState.operation1(); } public void operation2() { currentState.operation1(); } public void operation3() { currentState.operation1(); } } class State1 implements State { Context context; State1(Context context) { this.context = context; } public void operation1() { context.setState(context.state2); } public void operation2() { context.setState(context.state1); } public void operation3() { context.setState(context.state1); } public void print() { System.out.println("State1"); } } class State2 implements State { Context context; State2(Context context) { this.context = context; } public void operation1() { context.setState(context.state1); } public void operation2() { context.setState(context.state2); } public void operation3() { context.setState(context.state2); } public void print() { System.out.println("State2"); } } class StatePattern { public static void run() { System.out.println("*** State pattern ***"); Context stateMachine = new Context(); stateMachine.operation1(); stateMachine.operation2(); } } /**************************** State pattern end ************************/ /**************************** Proxy pattern start ************************ Proxy pattern provides a surrogate or placeholder for another object to control access to it Remote Proxy as used by RMI and CORBA has client stub and server skeleton Virutal Proxy for object that maybe expensive to create e.g An Image Loader that displays a message while images is being loaded Firewall Proxy, controls access to a set of network resources, protecting the subject from bad clients. Caching Proxy, provides temporary storage for results of operations that are expensive. It can also allow multiple clients to share the results to reduce computation or network latency Synchronization Proxy, provides safe access to a subject from multiple threads Complexity hiding proxy, aka Facade Proxy Copy on write proxy, controls the copying of the object by defering the copying of an object until it is required by a client. This is a variant of the virtual proxy */ interface Employee { String getName(); public void add(Employee employee); boolean isManager(); public void print(); } class EmployeeImpl implements Employee { String name; ArrayList subs = new ArrayList(); boolean manager; public EmployeeImpl(String name, boolean manager) { this.name = name; this.manager = manager; } public String getName() { return name; } public void add(Employee employee) { subs.add(employee); } public boolean isManager() { return manager; } public void print() { System.out.println(name + "=" + subs.size()); } } class EmployeeInvocationHandler implements InvocationHandler { Employee employee; public EmployeeInvocationHandler(Employee employee) { this.employee = employee; } public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException { System.out.println(" in Proxy invoke"); try { if (!employee.isManager() && method.getName().equals("add")) return null; else method.invoke(employee, args); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } } class ProxyPattern { public static Employee getEmployeeProxy(Employee employee) { return (Employee)Proxy.newProxyInstance(employee.getClass().getClassLoader(), employee.getClass().getInterfaces(), new EmployeeInvocationHandler(employee)); } public static void run() { System.out.println("*** Proxy pattern ***"); Employee larry = new EmployeeImpl("Larry", true); Employee curly = new EmployeeImpl("Curly", false); Employee moe = new EmployeeImpl("Moe", false); Employee larryProxy = getEmployeeProxy(larry); Employee curlyProxy = getEmployeeProxy(curly); Employee moeProxy = getEmployeeProxy(moe); larryProxy.add(curlyProxy); larryProxy.add(moeProxy); try { curlyProxy.add(moeProxy); } catch (Exception e) { System.out.println("Only Managers can add employees"); } larryProxy.print(); curlyProxy.print(); } } /**************************** Proxy pattern end ************************/ /*********************************************************************** A Compound Pattern combines two or more patterns into a solution that solves a recurring or general problem Model View Pattern View uses the Composite patterns as it consistes of nested windows/panels/textboxes/buttons The view is configured with the strategy. The controller provides the strategy as the view delegates the control to the controller The model implementes the Observer pattern as it informs the views when the state changes Bridge Pattern is used to vary not only your implementation but also your abstractions e.g different remote controls controlling different TV The Builder pattern allows you to encapsulate the construction of a product and allow it to be constructed in steps (A multi step factory) e.g A Vacation Package Planner The steps are bookHotel() bookPlane() bookCar() Chain of responsibility allows more that one object to handle a request e.g Email filter Flyweight pattern creates many virtual instances for one instance of a class e.g Image Thumbnail viewer where instead of having on object per thumbnail to speed up you can have one virtual Thumbnail viewer Interpreter pattern is used for building an interperter for a language class Expression { interpret(context) } class FooCommand extends Expression { interpret(context) } Mediator Pattern centralizes complex communications and control between related objects like a controller in an MVC pattern Memento Pattern returns an object to one of its previous states e.g for an undo request Prototype Pattern is used when creating an instance of a class is either expensive or complicated typically use a lookup service and return a clone Visitor pattern adds capabilites to a composite of objects when encapsulation is not important */ public class Patterns { public static void main(String[] args) { StrategyPattern.run(); ObserverPattern.run(); DecoratorPattern.run(); FactoryPattern.run(); SingletonPattern.run(); CommandPattern.run(); AdapterPattern.run(); TemplateMethodPattern.run(); IteratorAndCompositePattern.run(); StatePattern.run(); ProxyPattern.run(); } }