Design Patterns
CS351 - Software Engineering (AY2007)Slide 2 Behavioral patterns Suppose we have an aggregate data structure and we wish to access the components without revealing the structure of the aggregate –e.g. it would be nice to be able to write something like: for (Iterator i = s.iterator() i.hasNext();) { x=i.next();... –e.g. we may have a Set data structure and wish to examine the elements of the set without revealing whether they are stored as an array, linked list, etc. –Solution is to define an Iterator
CS351 - Software Engineering (AY2007)Slide 3 Iterator – object behavioral Synopsis: Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation Context: useful for accessing the components of any data structure, e.g. set, list, tree Forces: Use the Iterator pattern: –to access an aggregate object’s contents without exposing its internal representation –to support multiple traversals of aggregate objects –to provide a uniform interface for traversing different aggregate structures (i.e. to support polymorphic iteration)
CS351 - Software Engineering (AY2007)Slide 4 Iterator – object behavioral Solution: –Iterator – defines an interface for accessing and traversing elements –ConcreteIterator (e.g. PTListIterator) – implements the Iterator interface; keeps track of the current position in the traversal of the aggregate –Aggregate – defines an interface for creating an Iterator object –ConcreteAggregate (e.g. PTList) – implements the Iterator creation interface to return an instance of the proper ConcreteIterator
CS351 - Software Engineering (AY2007)Slide 5 Example: a list iterator PTListIterator will need to have a reference to the list (as indicated by the arrow in the diagram) For scoping reasons (in Java), the PTListIterator will be declared as a public inner class of PTList—only then will the hidden components of PTList be accessible to the iterator, cf. friend in C++
CS351 - Software Engineering (AY2007)Slide 6 Iterator – object behavioral Consequences: There are 3 important consequences: –It supports variations in the traversal of an aggregate. Complex data structures may be traversed in many ways. Different iterators can be defined for different kinds of traversal –Iterators simplify the Aggregate interface. The Aggregate does not need to supply extra functions for iteration, since they are now available in a separate class. –More than one traversal can be pending on an aggregate. This is because each iterator keeps track of its own traversal state. The same effect would be more difficult if the aggregate stored the traversal state. You should query the robustness of the iterator – what happens if the aggregate is changed during traversal?
CS351 - Software Engineering (AY2007)Slide 7 Java code for an iterator Code added to the PTSet class import java.util.Iterator;// Java has the interface defined import java.util.Set; class PTSet implements Set {// class definition … public class ElementIterator implements Iterator { // use the Iterator interface int currelt = 0; public boolean hasNext() { // part of the Iterator interface return currelt < numElements(); } public Object next() { // part of the Iterator interface Object result = null; // result will require coercion if (hasNext()) { result = item(currelt); currelt = currelt+1; } return result; } public Iterator iterator() {// function to create an iterator return new ElementIterator(); } Generate iterator Use iterator Interface of Java
CS351 - Software Engineering (AY2007)Slide 8 Java code for an iterator Code added to the client class import java.util.Iterator; class Client { // class definition for some client … PTSet s = new PTSet(); // will process elements of set s … for (Iterator iter = s.makeElementIterator(); iter.hasNext(); ) { // generate the iterator Element e=(Element)iter.next(); …} … }
CS351 - Software Engineering (AY2007)Slide 9 Decorator Pattern Sometimes we want to add responsibilities to individual objects rather than every object of a specific class. For example, we may want to dynamically decorate a text window with scroll bars if the text exceeds the window size, but inheritance would provide scroll bars to every text window. We want the ability to dynamically add or remove a decoration. The decorator conforms to the interface of its component so that its presence is transparent to the user. The decorator forwards requests to the component and may perform additional actions before and/or after forwarding. Decorations can be nested recursively so that an unlimited number of responsibilities can be added (e.g., scroll bars, border and shadowing may all be separate decorations).
CS351 - Software Engineering (AY2007)Slide 10 Decorator Pattern Decorations can appear anywhere the base component can. In this way clients can not tell the difference between a decorated and an undecorated component, and hence they don’t (can’t) depend on the decoration. Decorations are often used with graphical user interfaces, but they can also be used to decorate data structures such as graphs (to assist with graph traversal), etc.
CS351 - Software Engineering (AY2007)Slide 11 Decorator Pattern - applicability Use Decorator to add responsibilities to individual objects dynamically and transparently without affecting other objects. Use Decorator for responsibilities that can be removed/withdrawn. Use Decorator when extension through subclassing is impractical or undesirable.
CS351 - Software Engineering (AY2007)Slide 12 Decorator Pattern - structure Component Operation() ConcreteComponent Operation() Decoration Operation() ConcreteDecoratorB Operation() AddedBehavior() ConcreteDecoratorA AddedState Operation()
CS351 - Software Engineering (AY2007)Slide 13 Decorator Pattern - structure Component: defines the interface for objects that can have responsibilities added to them dynamically. ConcreteComponent: defines an object to which additional responsibilties can be attached. Decorator: maintains a reference to a component object and defines an interface that conforms to the Component interface. ConcreteDecorator: adds responsibilities to the component. Collorations –Decorator forwards requests onto the Component object. It may optionally perform additional operations before and after forwarding the request.
CS351 - Software Engineering (AY2007)Slide 14 Decorator Pattern - consequences At least 2 key benefits and 2 liabilities. –More flexibility than static inheritance. –Avoids feature laden classes high up in the hierarchy. –A document and its component are not identical. –Lots of little objects.
CS351 - Software Engineering (AY2007)Slide 15 Decorator Pattern - implementation Interface conformance Omitting the abstract Decorator class. There is no need to define an abstract Decorator class when all you want is to add a single responsibility. Keeping component classes lightweight. Changing the skin of an object versus changing its guts - think of the decorator pattern as a skin over an object that changes its behavior.
CS351 - Software Engineering (AY2007)Slide 16 Decorator Pattern - sample code Assume that there is a Component class called VisualComponent. There we could write the following C++ code. class VisualComponent { public: VisualComponent(); virtual void Draw(); virtual void Resize(); // … }; class Decorator : public VisualComponent { public: Decorator(VisualComponent*); virtual void Draw(); virtual void Resize(); // … private: VisualCOmponent* _component; }; Decorator decorates the VisualComponent referenced by _component which is initialized in the constructor.
CS351 - Software Engineering (AY2007)Slide 17 Decorator Pattern – sample code Decorator provides a default implementation that simply passes the request to _component. void Decorator::Draw () { _component->Draw(); } void Decorator::Resize () { _component->Resize(); }
CS351 - Software Engineering (AY2007)Slide 18 Decorator Pattern – sample code Subclasses of Decorator define the specific decorations. class BorderDecorator : public Decorator { public: BorderDecorator(VisualComponent*, int borderwidth); virtual void Draw(); private: void DrawBorder(int); private: int _width; } void BorderDecorator::Draw () { Decorator::Draw(); DrawBorder(_width); } Similar classes for ScrollDecorator and DropShadowDecorator. These can be composed to combine effects.
CS351 - Software Engineering (AY2007)Slide 19 Decorator Pattern – sample code First we need a way to put a visual component into a window object. Let’s assume our Window class has a SetContents operation for this purpose. void Window::SetContents (VisualComponent* content){ // … } Now we can create a text view and put a window in it. Window* window = new Window; TextView* textView = new TextView; TextView is a VisualComponent, which lets us put it in the window. Window->SetContents(textView);
CS351 - Software Engineering (AY2007)Slide 20 Decorator Pattern – sample code But we want a bordered and scrollable TextView. So we need to decorate it accordingly before putting it into the window. Window->SetContents( new BorderDecorator( new ScrollDecorator(textView), 1 ) ); Because Window accesses its content through the VisualComponent interface, it is unaware of the decorators presence. Related patterns: Adapter, Composite, Strategy.