32
Design Patterns II 1

Design Patterns II

  • Upload
    trung

  • View
    30

  • Download
    0

Embed Size (px)

DESCRIPTION

Design Patterns II. Behavioral Pattern Visitor: intent and structure. Represent an operation to be performed on the elements of an object structure. Visitor: structure. Visitor: participants. Visitor (IChef) - PowerPoint PPT Presentation

Citation preview

Page 1: Design Patterns II

Design PatternsII

1

Page 2: Design Patterns II

Behavioral PatternVisitor: intent and structure

Represent an operation to be performed on the elements of an object structure.

Represent an operation to be performed on the elements of an object structure.

2

Page 3: Design Patterns II

Visitor: structure

3

Page 4: Design Patterns II

Visitor: participantsVisitor (IChef)

declares a Visit operation for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class that sends the Visit request to the visitor.

ConcreteVisitor (ChefWong, ChefZung) implements each operation declared by Visitor.

Element (AEater) defines an Accept operation that takes a visitor as an argument.

ConcreteElement (Vegetarian, Carnivore ) implements an Accept operation that takes a visitor as an argument.

ObjectStructure may provide a high-level interface to allow the visitor to visit its elements

4

Page 5: Design Patterns II

Visitor: collaborations

5

Page 6: Design Patterns II

Visitor: implementation/* Visitor */interface IChef  {   String cookVeggie(Vegetarian h, Integer n);   String cookMeat(Carnivore h, Integer n);}/* Concrete Visitor 1 */class ChefWong implements IChef { public String cookVeggie(Vegetarian h, Integer n) {       return  n + ":" + h.getBroccoli() + ", " + h.getSalt();   }   public String cookMeat(Carnivore h, Integer n) {       return  n + ":" + h.getMeat() + ", " + h.getPepper();   }}/* Concrete Visitor 2 */class ChefZung implements IChef { public String cookVeggie(Vegetarian h, Integer n) {       return  n + ":" + h.getCorn() + ", " + h.getSalt();   }   public String cookMeat(Carnivore h, Integer n) {       return  n + ":" + h.getChicken() + ", " + h.getPepper();   }}

/* Visitor */interface IChef  {   String cookVeggie(Vegetarian h, Integer n);   String cookMeat(Carnivore h, Integer n);}/* Concrete Visitor 1 */class ChefWong implements IChef { public String cookVeggie(Vegetarian h, Integer n) {       return  n + ":" + h.getBroccoli() + ", " + h.getSalt();   }   public String cookMeat(Carnivore h, Integer n) {       return  n + ":" + h.getMeat() + ", " + h.getPepper();   }}/* Concrete Visitor 2 */class ChefZung implements IChef { public String cookVeggie(Vegetarian h, Integer n) {       return  n + ":" + h.getCorn() + ", " + h.getSalt();   }   public String cookMeat(Carnivore h, Integer n) {       return  n + ":" + h.getChicken() + ", " + h.getPepper();   }}

6

Page 7: Design Patterns II

Visitor: implementation (cont.)/* Element */abstract class AEater {  String getSalt() { return "salt"; }   String getPepper() { return "pepper"; }    abstract String order(IChef c, Integer n);  }/* Concrete Element 1 */class Vegetarian extends AEater {  String getBroccoli() { return "broccoli"; }    String getCorn() { return "corn"; }  String order(IChef c, Integer n) { return c.cookVeggie(this, n); }}/* Concrete Element 2 */class Carnivore extends AEater {  String getMeat() { return "steak"; }    String getChicken() { return "cornish hen"; }   String order(IChef c, Integer n) { return c.cookMeat(this, n); }}/* Client */AEater John = new Carnivore(); AEater Mary = new Vegetarian();Mary.order(new ChefWong(), 2); John.order(new ChefZung(), 3);

/* Element */abstract class AEater {  String getSalt() { return "salt"; }   String getPepper() { return "pepper"; }    abstract String order(IChef c, Integer n);  }/* Concrete Element 1 */class Vegetarian extends AEater {  String getBroccoli() { return "broccoli"; }    String getCorn() { return "corn"; }  String order(IChef c, Integer n) { return c.cookVeggie(this, n); }}/* Concrete Element 2 */class Carnivore extends AEater {  String getMeat() { return "steak"; }    String getChicken() { return "cornish hen"; }   String order(IChef c, Integer n) { return c.cookMeat(this, n); }}/* Client */AEater John = new Carnivore(); AEater Mary = new Vegetarian();Mary.order(new ChefWong(), 2); John.order(new ChefZung(), 3);

7

Page 8: Design Patterns II

Visitor: consequencesConsequences:• Visitor lets you define a new operation without changing the

classes of the elements on which it operates.

• A visitor gathers related operations and separates unrelated ones.

• Adding new ConcreteElement classes is hard.

• Visiting across class hierarchies.

• Accumulating state.

• Breaking encapsulation. 8

Page 9: Design Patterns II

Structural PatternDecorator: intent and structure

Decorators provide a flexible alternative to subclassing for extending functionality.

Decorators provide a flexible alternative to subclassing for extending functionality.

9

Page 10: Design Patterns II

Decorator: participantsComponent (Window)

defines the interface for objects that can have responsibilities added to them dynamically.

ConcreteComponent (SimpleWindow) defines an object to which additional responsibilities can be attached.

Decorator (WindowDecorator) maintains a reference to a Component object and defines an interface

that conforms to Component's interface.

ConcreteDecorator (ScrollBarDecorator, BorderDecorator) adds responsibilities to the component.

10

Page 11: Design Patterns II

Decorator: implementation/* Component */public interface Window { public void draw();}/* Concrete Component */public class SimpleWindow implements Window { public void draw() {…} public String toString() { return "Simple window"; }}/* Decorator */abstract class WindowDecorator implements Window { protected Window w; public WindowDecorator (Window w) { this.w = w; }}/* Concrete Decorator 1 */class ScrollBarDecorator extends WindowDecorator { public ScrollBarDecorator(Window w) { super(w); } public void draw() { drawScrollBar(); w.draw(); } private void drawScrollBar() {…} public String toString() { return w + " including scroll bar"; }}

/* Component */public interface Window { public void draw();}/* Concrete Component */public class SimpleWindow implements Window { public void draw() {…} public String toString() { return "Simple window"; }}/* Decorator */abstract class WindowDecorator implements Window { protected Window w; public WindowDecorator (Window w) { this.w = w; }}/* Concrete Decorator 1 */class ScrollBarDecorator extends WindowDecorator { public ScrollBarDecorator(Window w) { super(w); } public void draw() { drawScrollBar(); w.draw(); } private void drawScrollBar() {…} public String toString() { return w + " including scroll bar"; }}

11

Page 12: Design Patterns II

Decorator: implementation (cont.)/* Concrete Decorator 2 */public class BorderDecorator extends WindowDecorator { public BorderDecorator(Window w) { super(w); } public void draw() { drawBorder(); w.draw(); } private void drawBorder() {…} public String getDescription(){ return w + " including border"; }}

/* Client */public class Client { public void run() { Window decoratedWindow = new ScrollBarDecorator(

new BorderDecorator(new SimpleWindow()));

System.out.println(decoratedWindow); }}

/* Concrete Decorator 2 */public class BorderDecorator extends WindowDecorator { public BorderDecorator(Window w) { super(w); } public void draw() { drawBorder(); w.draw(); } private void drawBorder() {…} public String getDescription(){ return w + " including border"; }}

/* Client */public class Client { public void run() { Window decoratedWindow = new ScrollBarDecorator(

new BorderDecorator(new SimpleWindow()));

System.out.println(decoratedWindow); }}

12

Page 13: Design Patterns II

Decorator: consequencesConsequences:

• More flexibility than static inheritance.

• Avoids feature-laden classes high up in the hierarchy.

• A decorator and its component aren't identical.

• Lots of little objects.

13

Page 14: Design Patterns II

Structural PatternAdapter: intent and structure

Convert the interface of a class into another interface clients expect.

Convert the interface of a class into another interface clients expect.

14

Page 15: Design Patterns II

Adapter: participantsTarget (Stack)

defines the domain-specific interface that Client uses.

Client collaborates with objects conforming to the Target interface.

Adaptee (DList) defines an existing interface that needs adapting.

Adapter (DListImpStack) adapts the interface of Adaptee to the Target interface.

15

Page 16: Design Patterns II

Class Adapter: implementation/* Target */interface Stack<T> { void push (T o); T pop (); T top ();}

/* Adaptee */public class DList<T> { public void insertHead (T o) {…} public void insertTail (T o) {…} public T removeHead () {…} public T removeTail () {…} public T getHead () {…} public T getTail () {…}}

/* Adapter */public class DListImpStack<T> extends DList<T> implements Stack<T> { public void push (T o) { insertTail (o); } public T pop () { return removeTail (); } public T top () { return getTail (); } }

/* Target */interface Stack<T> { void push (T o); T pop (); T top ();}

/* Adaptee */public class DList<T> { public void insertHead (T o) {…} public void insertTail (T o) {…} public T removeHead () {…} public T removeTail () {…} public T getHead () {…} public T getTail () {…}}

/* Adapter */public class DListImpStack<T> extends DList<T> implements Stack<T> { public void push (T o) { insertTail (o); } public T pop () { return removeTail (); } public T top () { return getTail (); } }

16

Page 17: Design Patterns II

Adapter: consequencesConsequences:

• A class adapter• a class adapter won't work when we want to adapt a class

and all its subclasses.• lets Adapter override some of Adaptee's behavior• no additional pointer indirection is needed to get to the

adaptee.

• An object adapter• lets a single Adapter work with many Adaptees• makes it harder to override Adaptee behavior.

17

Page 18: Design Patterns II

Behavioral PatternCommand: intent and structure

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or

log requests, and support undoable operations.

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or

log requests, and support undoable operations.

18

Page 19: Design Patterns II

Command: participantsCommand (Command)

declares an interface for executing an operation.

ConcreteCommand (MoveUpCommand, MoveRightCommand) defines a binding between a Receiver object and an action. implements Execute by invoking the corresponding operation(s) on Receiver.

Client (Game) creates a ConcreteCommand object and sets its receiver.

Invoker (Game) asks the command to carry out the request.

Receiver (GameBoard) knows how to perform the operations associated with carrying out a request. Any class may serve as a Receiver.

19

Page 20: Design Patterns II

Command: implementation/* Receiver */public class GameBoard { public int x = 0; public int y = 0; public static final int XMAX = 10; public static final int YMAX = 10; public void incX() { if (x < GameBoard.XMAX) ++x; } public void decX() { if (x > 0) --x; } public void incY() { if (y < GameBoard.YMAX) ++y; } public void decY() { if (y > 0) --y; }}

/* Command */public interface Command { void execute(); void undo();}

/* Concrete Command 1 */public class MoveUpCommand implements Command { private GameBoard gb; public MoveUpCommand(GameBoard gb) { this.gb = gb; } public void execute() { gb.incY(); } public void undo() { gb.decY(); }}

/* Receiver */public class GameBoard { public int x = 0; public int y = 0; public static final int XMAX = 10; public static final int YMAX = 10; public void incX() { if (x < GameBoard.XMAX) ++x; } public void decX() { if (x > 0) --x; } public void incY() { if (y < GameBoard.YMAX) ++y; } public void decY() { if (y > 0) --y; }}

/* Command */public interface Command { void execute(); void undo();}

/* Concrete Command 1 */public class MoveUpCommand implements Command { private GameBoard gb; public MoveUpCommand(GameBoard gb) { this.gb = gb; } public void execute() { gb.incY(); } public void undo() { gb.decY(); }}

20

Page 21: Design Patterns II

Command: implementation (cont.)/* Concrete Command 2 */public class MoveRightCommand implements Command { private GameBoard gb; public MoveRightCommand (GameBoard gb) { this.gb = gb; } public void execute() { gb.incX(); } public void undo() { gb.decX();}}

/* Invoker */public class Game { private GameBoard gb = new GameBoard(); private Command moveUpCommand; private Command moveLeftCommand; public Game() { moveUpCommand = new MoveUpCommand(gb); moveLeftCommand = new MoveRightCommand(gb); } public void action() { moveUpCommand.execute(); moveLeftCommand.execute(); }}

/* Concrete Command 2 */public class MoveRightCommand implements Command { private GameBoard gb; public MoveRightCommand (GameBoard gb) { this.gb = gb; } public void execute() { gb.incX(); } public void undo() { gb.decX();}}

/* Invoker */public class Game { private GameBoard gb = new GameBoard(); private Command moveUpCommand; private Command moveLeftCommand; public Game() { moveUpCommand = new MoveUpCommand(gb); moveLeftCommand = new MoveRightCommand(gb); } public void action() { moveUpCommand.execute(); moveLeftCommand.execute(); }}

21

Page 22: Design Patterns II

Command: consequencesConsequences:

• Command decouples the object that invokes the operation from the one that knows how to perform it.

• Commands are first-class objects. They can be manipulated and extended like any other object.

• You can assemble commands into a composite command.

• It's easy to add new Commands, because you don't have to change existing classes.

22

Page 23: Design Patterns II

Behavioral PatternObserver: intent and structure

Define a one-to-many dependency between objects so that when one object changes state, all its dependents

are notified and updated automatically.

Define a one-to-many dependency between objects so that when one object changes state, all its dependents

are notified and updated automatically.

23

Page 24: Design Patterns II

Observer: participantsSubject

knows its observers. Any number of Observer objects may observe a subject.

provides an interface for attaching and detaching Observer objects.

ConcreteSubject (PowerVector) stores state of interest to ConcreteObserver objects. sends a notification to its observers when its state changes.

Observer (IObserver) defines an updating interface for objects that should be notified of changes in a subject.

ConcreteObserver (SizeKeeper) maintains a reference to a ConcreteSubject object. stores state that should stay consistent with the subject's. implements the Observer updating interface to keep its state consistent

with the subject's.

24

Page 25: Design Patterns II

Observer: implementation/* Concrete Subject */public class PowerVector { private ArrayList<Object> items = new ArrayList<Object>(); private ArrayList<IObserver> observers =

new ArrayList<IObserver>(); public int size() { return items.size(); } public void addObserver(IObserver ob) { observers.add(ob); } public void add(Object o) { items.add(o); notifyObservers(); } public void remove(Object o) { items.remove(o); notifyObservers(); } public void notifyObservers() { for (IObserver ob: observers) ob.update(this); }}

/* Concrete Subject */public class PowerVector { private ArrayList<Object> items = new ArrayList<Object>(); private ArrayList<IObserver> observers =

new ArrayList<IObserver>(); public int size() { return items.size(); } public void addObserver(IObserver ob) { observers.add(ob); } public void add(Object o) { items.add(o); notifyObservers(); } public void remove(Object o) { items.remove(o); notifyObservers(); } public void notifyObservers() { for (IObserver ob: observers) ob.update(this); }}

25

Page 26: Design Patterns II

Observer: implementation (cont.)/* Observer */public interface IObserver { public void update(PowerVector subject);}/* Concrete Observer */public class SizeKeeper implements IObserver { private int size; public void update(PowerVector subject) { size = subject.size(); } public int size() { return size; }}/* Client */public class Client { private PowerVector v = new PowerVector(); public void run(){ v.addObserver(new SizeKeeper()); v.add(1); v.add(2); System.out.println(v.size()); }}

/* Observer */public interface IObserver { public void update(PowerVector subject);}/* Concrete Observer */public class SizeKeeper implements IObserver { private int size; public void update(PowerVector subject) { size = subject.size(); } public int size() { return size; }}/* Client */public class Client { private PowerVector v = new PowerVector(); public void run(){ v.addObserver(new SizeKeeper()); v.add(1); v.add(2); System.out.println(v.size()); }}

26

Page 27: Design Patterns II

Observer: consequencesConsequences:

• Abstract coupling between Subject and Observer.

• Support for broadcast communication.

• Unexpected updates.

27

Page 28: Design Patterns II

Behavioral PatternChain-of-Responsibility: intent and structure

Chain the receiving objects and pass the request along the chain until an object handles it.

Chain the receiving objects and pass the request along the chain until an object handles it.

28

Page 29: Design Patterns II

Chain-of-Responsibility: participantsHandler (Filter)

defines an interface for handling requests. (optional) implements the successor link.

ConcreteHandler (EvenFilter, PrimeFilter) handles requests it is responsible for. can access its successor. if the ConcreteHandler can handle the request, it does so; otherwise it

forwards the request to its successor.

Client (Client) initiates the request to a ConcreteHandler object on the chain.

29

Page 30: Design Patterns II

Chain-of-Responsibility: implementation/* Handler */public class Filter { private Filter next = null; public void attach(Filter other) { other.next = this.next; this.next = other; } public final void invoke(int v) { if (this.handle(v)) return; if (next != null) next.invoke(v); } public boolean handle(int v) { return false;}}/* Concrete Handler 1 */public class EvenFilter extends Filter { public boolean handle(int v) { return (v % 2 == 0);}}/* Concrete Handler 2 */public class PrimeFilter extends Filter { public boolean handle(int v) { for (int i = 2; i * i <= v; ++i) if (v % i == 0) return false; return true; }}

/* Handler */public class Filter { private Filter next = null; public void attach(Filter other) { other.next = this.next; this.next = other; } public final void invoke(int v) { if (this.handle(v)) return; if (next != null) next.invoke(v); } public boolean handle(int v) { return false;}}/* Concrete Handler 1 */public class EvenFilter extends Filter { public boolean handle(int v) { return (v % 2 == 0);}}/* Concrete Handler 2 */public class PrimeFilter extends Filter { public boolean handle(int v) { for (int i = 2; i * i <= v; ++i) if (v % i == 0) return false; return true; }}

30

Page 31: Design Patterns II

Chain-of-Responsibility: implementation (cont.)

/* Client */public class Client { private ArrayList<Integer> l = new ArrayList<Integer>(); private Filter chain = new Filter();

public Client() { chain.attach(new Filter() {

public boolean handle(int v) { l.add(v); return true;}

}); chain.attach(new EvenFilter()); chain.attach(new PrimeFilter()); } public void run() { for (int i = 0; i < 10; ++i)

chain.invoke(i); System.out.println("Size = " + l.size()); }}

/* Client */public class Client { private ArrayList<Integer> l = new ArrayList<Integer>(); private Filter chain = new Filter();

public Client() { chain.attach(new Filter() {

public boolean handle(int v) { l.add(v); return true;}

}); chain.attach(new EvenFilter()); chain.attach(new PrimeFilter()); } public void run() { for (int i = 0; i < 10; ++i)

chain.invoke(i); System.out.println("Size = " + l.size()); }}

31

Page 32: Design Patterns II

Chain-of-Responsibility: consequencesConsequences:

• Reduced coupling.

• Added flexibility in assigning responsibilities to objects.

• Receipt isn't guaranteed.

32