230 likes | 317 Views
Pattern Games. CS 236700: Software Design Winter 2004-2005/T9. Overview of the programs. Three similar programs Each one is actually a single collaboration The main goal: manage a Vector of integer values The programs are similar but not identical
E N D
Pattern Games CS 236700: Software Design Winter 2004-2005/T9
Overview of the programs • Three similar programs • Each one is actually a single collaboration • The main goal: manage a Vector of integer values • The programs are similar but not identical • The differences are in specific details of the required behavior • We will use Design Patterns to address the various needs: • Command • Observer • Chain-of-Responsibility
Participating classes • Client – the “application”. • Has a constructor and a run() method • Role: Client • PowerVector – Maintains a list of Objects • Role: Invoker, Concrete Subject, Concrete Handler • SizeKeeper – Notified when an add/remove request happens • Allows the client to obtain the size of the PowerVector object • Role: Receiver, Concrete Observer • Additional classes in each program • SizeCommand, IObserver, …
Skeleton of class PowerVector public class PowerVector { private Vector items_ = new Vector(); public PowerVector(...) { ... } public Object get(int index) { return items_.get(index); } public void add(Object o) { items_.add(o); } public void remove() { items_.remove(items_.size() - 1); } }
Skeleton of class Client public class Client { private PowerVector vec_; public Client() { ... } public void run() { // add 25 integers to vec_ (how?) // print size (how?) for(int i = 0; i < 3; ++i) vec_.remove(); // print size (how?) } public static void main(String[] args) { Client c = new Client(); c.run(); } }
1st program • In this program, class PowerVector has no getSize() method • A SizeKeeper object will monitor the size of the vector • We will use the Command pattern to notify the SizeKeeper object of add/remove operations
Command: intent Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
SizeKeeper public class SizeKeeper { private int size_ = 0; public void incSize(int diff) { size_ += diff; } public int getSize() { return size_; } }
ICommand, SizeCommand public interface ICommand { public void execute(); } public class SizeCommand implements ICommand { private int diff_; private SizeKeeper keeper_; public SizeCommand(SizeKeeper keeper, int diff) { diff_ = diff; keeper_ = keeper; } public void execute() { keeper_.incSize(diff_); } }
PowerVector public class PowerVector { private Vector items_ = new Vector(); private ICommand on_add_; private ICommand on_remove_; public PowerVector(ICommand on_add, ICommand on_remove) { on_add_ = on_add; on_remove_ = on_remove; } public void add(Object o) { items_.add(o); on_add_.execute(); // add notification } public void remove() { items_.remove(items_.size() - 1); on_remove_.execute(); // remove notification } }
Client public class Client { private PowerVector vec_; private SizeKeeper keeper_ = new SizeKeeper(); public Client() { ICommand onInc = new SizeCommand(keeper_, 1); ICommand onDec = new SizeCommand(keeper_, -1); vec_ = new PowerVector(onInc, onDec); } public void run() { for(int i = 0; i < 25; ++i) vec_.add(new Integer(i)); System.out.println("Size=" + keeper_.getSize()); for(int i = 0; i < 3; ++i) vec_.remove(); System.out.println("Size=" + keeper_.getSize()); } // main() omitted }
2nd program • Now, class PowerVector provides a getSize() method • SizeKeeper will use this method • => Tight-coupling between SizeKeepr and PowerVector • SizeKeeper is an observer of PowerVector
Observer: intent Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
IObserver, SizeKeeper public interface IObserver { public void update(PowerVector subject); } public class SizeKeeper implements IObserver { private int size_; public SizeKeeper() { } public void update(PowerVector subject) { size_ = subject.getSize(); } public int getSize() { return size_; } }
PowerVector public class PowerVector { private Vector items_ = new Vector(); private LinkedList observers_ = new LinkedList(); public PowerVector() { } public int getSize() { return items_.size(); } public void addObserver(IObserver o) { observers_.add(o); } public void add(Object o) { items_.add(o); for(Iterator i = observers_.iterator(); i.hasNext(); ) ((IObserver) i.next()).update(this); } // remove() is similarly implemented }
Client public class Client { private PowerVector vec_ = new PowerVector(); private SizeKeeper keeper_ = new SizeKeeper(); public Client() { vec_.addObserver(keeper_); } public void run() { for(int i = 0; i < 25; ++i) vec_.add(new Integer(i)); System.out.println("Size=" + keeper_.getSize()); for(int i = 0; i < 3; ++i) vec_.remove(); System.out.println("Size=" + keeper_.getSize()); } // main() omitted }
3rd program • At this stage, we would like to control the values added to the PowerVector object • The Chain-Of-Responsibility allows screening of requests • Client class will invoke an “add element” request • The request will propagate through a chain of request handlers • The last handler is the PowerVector object itself
Chain-of-Reponsibility: intent Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
RequestHandler public class RequestHandler { private RequestHandler next_ = null; public void attach(RequestHandler other) { other.next_ = this.next_; this.next_ = other; } public final void invoke(Integer val) { if(this.handle(val)) return; if(next_ != null) next_.invoke(val); } public boolean handle(Integer val) { return false; } }
EvenFilter, PrimeFilter public class EvenFilter extends RequestHandler { public boolean handle(Integer val) { return (val.intValue() % 2 == 0); } } public class PrimeFilter extends RequestHandler { public boolean handle(Integer val) { int n = val.intValue(); for(int i = 2; i * i <= n; ++i) { if(n % i == 0) return false; } return true; } }
PowerVector • High degree of coherency in PowerVector • Is not concerned with notification issues public class PowerVector { private Vector items_ = new Vector(); public PowerVector() { } public Object get(int index) { return items_.get(index); } public void add(Object o) { items_.add(o); } public void remove() { items_.remove(items_.size() - 1); } public int getSize() { return items_.size(); } }
Client public class Client { private PowerVector vec_ = new PowerVector(); private RequestHandler chain_ = new RequestHandler(); public Client() { chain_.attach(new RequestHandler() { public boolean handle(Integer val) { vec_.add(val); return true; } }); chain_.attach(new EvenFilter()); chain_.attach(new PrimeFilter()); } public void run() { for(int i = 0; i < 25; ++i) chain_.invoke(new Integer(i)); System.out.println("Size=" + vec_.getSize()); for(int i = 0; i < 3; ++i) vec_.remove(); System.out.println("Size=" + vec_.getSize()); }
Summary • The three patterns allow modeling of different situations • Obviously, they can be used together to get a combined effect • Command: • An invoker does not know who is the actual receiver • An invoker does not know which method should be called • Observer: • Several observers are all interested in a single object • Chain-of-Responsibility • Several handlers are all interested in a single request • The chain represents a single request • A handler does not know who is the actual invoker