2Software Quality Management
Outline
Behavioral Patterns• Flyweight• Memento• Visitor
3Software Quality Management
Design Pattern SpacePurpose
Creational Structural Behavioral
Class Adapter
Object AdapterBridgeCompositeDecoratorFaçadeProxy
Scope Factory Method InterpreterTemplate Method
Abstract FactoryBuilderPrototypeSingleton
Chain of ResponsibilityCommandIteratorMediatorMementoFlyweightObserverStateStrategyVisitor
4Software Quality Management
Flyweight
Intent• Use sharing to support large numbers of fine-
grained objects efficiently• Some applications could benefit from using
objects throughout their design, but a naive implementation would be prohibitively expensive
5Software Quality Management
Motivation (1/5)
For example:• Most document editor implementations have text
formatting and editing facilities that are modularized to some extent
• Object-oriented document editors typically use objects to represent embedded elements like tables and figures
• However, they usually stop short of using an object for each character in the document, even though doing so would promote flexibility at the finest levels in the application
6Software Quality Management
Motivation (2/5)
A flyweight is a shared object that can be used in multiple contexts simultaneouslyThe flyweight acts as an independent object in each context• It is indistinguishable from an instance of the
object that is not shared• Flyweights cannot make assumptions about
the context in which they operate
7Software Quality Management
Motivation (3/5)
The key concept here is the distinction between intrinsic and extrinsic state:• Intrinsic state is stored in the flyweight; it consists of
information that's independent of the flyweight's context, thereby making it sharable
• Extrinsic state depends on and varies with the flyweight's context and therefore can't be shared. Client objects are responsible for passing extrinsic state to the flyweight when it needs it
8Software Quality Management
Motivation (4/5)
9Software Quality Management
Motivation (5/5)
10Software Quality Management
ApplicabilityThe Flyweight pattern's effectiveness depends heavily on how and where it is usedApply the Flyweight pattern when all of the following are true:• An application uses a large number of objects• Storage costs are high because of the sheer quantity of objects.• Most object state can be made extrinsic• Many groups of objects may be replaced by relatively few shared
objects once extrinsic state is removed • The application doesn't depend on object identity. Since
flyweight objects may be shared, identity tests will return truefor conceptually distinct objects
11Software Quality Management
Structure (1/2)
12Software Quality Management
Structure (2/2)
The following object diagram shows how flyweights are share:
13Software Quality Management
Participants (1/3)
Flyweight• Declares an interface through which flyweights can
receive and act on extrinsic state
ConcreteFlyweight (Character) • Implements the Flyweight interface and adds storage
for intrinsic state, if any. A ConcreteFlyweight object must be sharable. Any state it stores must be intrinsic; that is, it must be independent of the ConcreteFlyweight object's context
14Software Quality Management
Participants (2/3)UnsharedConcreteFlyweight (Row, Column) • Not all Flyweight subclasses need to be shared. The
Flyweight interface enables sharing; it doesn't enforce it. It's common for UnsharedConcreteFlyweightobjects to have ConcreteFlyweight objects as children at some level in the flyweight object structure (as the Row and Column classes have)
FlyweightFactory• Creates and manages flyweight objects• Ensures that flyweights are shared properly. When a
client requests a flyweight, the FlyweightFactoryobject supplies an existing instance or creates one, if none exists
15Software Quality Management
Participants (3/3)
Client• Maintains a reference to flyweight(s)• Computes or stores the extrinsic state of
flyweight(s)
16Software Quality Management
Collaborations (1/2)
State that a flyweight needs to function must be characterized as either intrinsic or extrinsic• Intrinsic state is stored in the
ConcreteFlyweight object• Extrinsic state is stored or computed by Client
objects Clients pass this state to the flyweight when they invoke its operations
17Software Quality Management
Collaborations (2/2)
Clients should not instantiate ConcreteFlyweights directlyClients must obtain ConcreteFlyweightobjects exclusively from the FlyweightFactory object to ensure they are shared properly
18Software Quality Management
Consequences (1/2)
Flyweights may introduce run-time costs associated with transferring, finding, and/or computing extrinsic state, especially if it was formerly stored as intrinsic stateHowever, such costs are offset by space savings, which increase as more flyweights are share
19Software Quality Management
Consequences (2/2)
Storage savings are a function of several factors:• The reduction in the total number of instances
that comes from sharing• The amount of intrinsic state per object
whether extrinsic state is computed or stored
20Software Quality Management
Implementation issues (1/3)
Removing extrinsic state• The pattern's applicability is determined largely by
how easy it is to identify extrinsic state and remove it from shared objects
• Removing extrinsic state will not help reduce storage costs if there are as many different kinds of extrinsic state as there are objects before sharing
• Ideally, extrinsic state can be computed from a separate object structure, one with far smaller storage requirements
21Software Quality Management
Implementation issues (2/3)
Managing shared objects• Because objects are shared, clients should not
instantiate them directly• FlyweightFactory lets clients locate a particular
flyweight• FlyweightFactory objects often use an associative
store to let clients look up flyweights of interestFor example, the flyweight factory in the document editor example can keep a table of flyweights indexed by character codes. The manager returns the proper flyweight given its code, creating the flyweight if it does not already exist
22Software Quality Management
Implementation issues (3/3)
23Software Quality Management
Flyweight Example (1/7)Suppose we want to draw a small folder icon with a name under it for each person in a an organizationIf this is a large organization, there could be a large number of such icons, but they are actually all the same graphical imageEven if we have two icons, one for “is Selected”and one for “not Selected” the number of different icons is smallIn such a system, having an icon object for each person, with its own coordinates, name and selected state is a waste of resources
24Software Quality Management
Flyweight Example (2/7)
Instead, we create a FolderFactory that returns either the selected or the unselected folder drawing class, but does not create additional instances once one of each has been created
25Software Quality Management
Flyweight Example (3/7)class FolderFactory {
Folder unSelected, Selected;
public FolderFactory() {
Color brown = new Color(0x5f5f1c);Selected = new Folder(brown);unSelected = new Folder(Color.yellow);
}
public Folder getFolder(boolean isSelected) {
if (isSelected)return Selected;
elsereturn unSelected;
}}
26Software Quality Management
Flyweight Example (4/7)class Folder extends JPanel {
private Color color;final int W = 50, H = 30;
public Folder(Color c) {color = c;
}
public void Draw(Graphics g, int tx, int ty, String name) {
g.setColor(Color.black); //outlineg.drawRect(tx, ty, W, H);g.drawString(name, tx, ty + H+15); //titleg.setColor(color); //fill rectangleg.fillRect(tx+1, ty+1, W-1, H-1);g.setColor(Color.lightGray); //bend line
27Software Quality Management
Flyweight Example (5/7)
g.drawLine(tx+1, ty+H-5, tx+W-1, ty+H-5);g.setColor(Color.black); //shadow linesg.drawLine(tx, ty+H+1, tx+W-1, ty+H+1);g.drawLine(tx+W+1, ty, tx+W+1, ty+H);g.setColor(Color.white); //highlight linesg.drawLine(tx+1, ty+1, tx+W-1, ty+1);g.drawLine(tx+1, ty+1, tx+1, ty+H-1);
}}
28Software Quality Management
Flyweight Example (6/7)public void paint(Graphics g) {Folder f;String name;int j = 0; //count number in rowint row = Top; //start in upper leftint x = Left;//go through all the names and foldersfor (int i = 0; i< names.size(); i++) {
name = (String)names.elementAt(i);if(name.equals(selectedName))
f = fact.getFolder(true);else
f = fact.getFolder(false);//have that folder draw itself at this spotf.Draw(g, x, row, name);x = x + HSpace; //change to next posnj++;
29Software Quality Management
Flyweight Example (7/7)if (j >= HCount) //reset for next row {
j = 0;row += VSpace;x = Left;
}}
}
30Software Quality Management
Flyweight Uses in JavaFlyweights are not frequently used at the application level in JavaThey are more of a system resource management technique, used at a lower level than Java. • However, it is useful to recognize that this technique exists so
you can use it if you need itOne place where we have already seen the Flyweight is in the cell renderer code we use for tables and list boxes• Usually the cell renderer is just a JLabel, but there may be two
or three types of labels or renderers for different colors or fonts. However, there are far fewer renderers than there are cells in the table or list
31Software Quality Management
Memento
Intent• Without violating encapsulation, capture and
externalize an object's internal state so that the object can be restored to this state later
Also Known As• Token
32Software Quality Management
Motivation (1/3)
Sometimes it is necessary to record the internal state of an objectThis is required when implementing checkpoints and undo mechanisms that let users back out of tentative operations or recover from errorsYou must save state information somewhere so that you can restore objects to their previous states
33Software Quality Management
Motivation (2/3)
Objects normally encapsulate some or all of their state, making it inaccessible to other objects and impossible to save externallyExposing this state would violate encapsulation, which can compromise the application's reliability and extensibility
34Software Quality Management
Motivation (3/3)
Example: Constraint solver
35Software Quality Management
Applicability
Use the Memento pattern when a snapshot of (some portion of) an object's state must be saved so that it can be restored to that state laterA direct interface to obtaining the state would expose implementation details and break the object's encapsulation
36Software Quality Management
Structure
37Software Quality Management
Participants (1/2)Memento (SolverState) • Stores internal state of the Originator object. The
memento may store as much or as little of the originator's internal state as necessary at its originator's discretion
• Protects against access by objects other than the originator. Mementos have effectively two interfaces. Caretaker sees a narrow interface to the Memento—it can only pass the memento to other objects. Originator, in contrast, sees a wide interface, one that lets it access all the data necessary to restore itself to its previous state. Ideally, only the originator that produced the memento would be permitted to access the memento's internal state.
38Software Quality Management
Participants (2/2)
Originator (ConstraintSolver) • Creates a memento containing a snapshot of
its current internal state• Uses the memento to restore its internal state
Caretaker (undo mechanism) • Is responsible for the memento's safekeeping• Never operates on or examines the contents
of a memento
39Software Quality Management
Collaborations
40Software Quality Management
Consequences (1/4)
Preserving encapsulation boundaries• Memento avoids exposing information that
only an originator should manage but that must be stored nevertheless outside the originator. The pattern shields other objects from potentially complex Originator internals, thereby preserving encapsulation boundaries
41Software Quality Management
Consequences (2/4)
It simplifies Originator• In other encapsulation-preserving designs,
Originator keeps the versions of internal state that clients have requested. That puts all the storage management burden on Originator. Having clients manage the state they ask for simplifies Originator and keeps clients from having to notify originators when they are done
42Software Quality Management
Consequences (3/4)
Using mementos might be expensive• Mementos might incur considerable overhead
if Originator must copy large amounts of information to store in the memento or if clients create and return mementos to the originator often enough
• Unless encapsulating and restoring Originator state is cheap, the pattern might not be appropriate
43Software Quality Management
Consequences (4/4)
Defining narrow and wide interfaces• It may be difficult in some languages to ensure that
only the originator can access the memento's state
Hidden costs in caring for mementos• A caretaker is responsible for deleting the mementos
it cares for. However, the caretaker has no idea how much state is in the memento. Hence an otherwise lightweight caretaker might incur large storage costs when it stores mementos
44Software Quality Management
Implementation issues (1/2)
Language support • Mementos have two interfaces: a wide one for
originators and a narrow one for other objects. Ideally the implementation language will support two levels of static protection. C++ lets you do this by making the Originator a friend of Memento and making Memento's wide interface private. Only the narrow interface should be declared public
45Software Quality Management
Implementation issues (2/2)
Storing incremental changes• When mementos get created and passed back
to their originator in a predictable sequence, then Memento can save just the incremental change to the originator's internal state
46Software Quality Management
C++ Memento Example (1/4)
MoveCommand classclass MoveCommand {
public: MoveCommand(Graphic* target, const Point& delta); void Execute(); void Unexecute();
private: ConstraintSolverMemento* _state; Point _delta; Graphic* _target;
};
47Software Quality Management
C++ Memento Example (2/4)Constraint Solver class
class ConstraintSolver {
public: static ConstraintSolver* Instance(); void Solve(); void AddConstraint(Graphic* startConnection,
Graphic* endConnection ); void RemoveConstraint(Graphic* startConnection,
Graphic* endConnection ); ConstraintSolverMemento* CreateMemento(); void SetMemento(ConstraintSolverMemento*);
private: // nontrivial state and operations for enforcing // connectivity semantics
};
48Software Quality Management
C++ Memento Example (3/4)
ConstraintSolverMemento class
class ConstraintSolverMemento {
public: virtual ~ConstraintSolverMemento();
private:
friend class ConstraintSolver; ConstraintSolverMemento(); // private constraint
// solver state };
49Software Quality Management
C++ Memento Example (4/4)MoveCommand methods
void MoveCommand::Execute () { ConstraintSolver* solver = ConstraintSolver::Instance(); state = solver->CreateMemento(); // create a memento target->Move(_delta); solver->Solve();
}
void MoveCommand::Unexecute () { ConstraintSolver* solver = ConstraintSolver::Instance();target->Move(-_delta); solver->SetMemento(_state); // restore solver state solver->Solve();
}
50Software Quality Management
Java Memento Example (1/10)
Java does not support friend classesBut a privileged access to a class is possible using a little known and infrequently used protection mode:• Variables with no declaration are treated as private
protected• Other classes can access public variables, and derived
classes can access protected variables. However, another class in the same module can access protected or private-protected variables
51Software Quality Management
Java Memento Example (2/10)
Consider a simple prototype of a graphics drawing program that creates rectangles, and allows you to select them and move them around by dragging them with the mouseThis program has a toolbar containing three buttons: • Rectangle• Undo • Clear
52Software Quality Management
Java Memento Example (3/10)
Graphical interface
53Software Quality Management
Java Memento Example (4/10)visRectangle Class
public class visRectangle {int x, y, w, h;Rectangle rect;boolean selected;
public visRectangle(int xpt, int ypt) {x = xpt; y = ypt; //save locationw = 40; h = 30; //use default sizesaveAsRect();
}
public void setSelected(boolean b) {selected = b;
}
private void saveAsRect() {rect = new Rectangle(x-w/2, y-h/2, w, h);
}
54Software Quality Management
Java Memento Example (5/10)public void draw(Graphics g) {
g.drawRect(x, y, w, h);if (selected) { //draw “handles”
g.fillRect(x+w/2, y-2, 4, 4);g.fillRect(x-2, y+h/2, 4, 4);g.fillRect(x+w/2, y+h-2, 4, 4);g.fillRect(x+w-2, y+h/2, 4, 4);
} }
public boolean contains(int x, int y) {
return rect.contains(x, y);}
public void move(int xpt, int ypt) {
x = xpt; y = ypt;saveAsRect();
}
55Software Quality Management
Java Memento Example (6/10)
The Memento class, which is contained in the same file, visRectangle.java, has access to the position and size variables
class Memento {
visRectangle rect;//saved fields- remember internal fields//of the specified visual rectangleint x, y, w, h;
56Software Quality Management
Java Memento Example (7/10)public Memento(visRectangle r) {
rect = r; //Save copy of instancex = rect.x; y = rect.y; //save positionw = rect.w; h = rect.h; //and size
}
public void restore() {
//restore the internal state of//the specified rectanglerect.x = x; rect.y = y; //restore positionrect.h = h; rect.w = w; //restore size
}
}
57Software Quality Management
Java Memento Example (8/10)Creation of a rectangle
public void createRect(int x, int y) {
unpick(); //make sure no rectangle is selectedif (startRect) { //if rect button is depressed
Integer count = new Integer(drawings.size());undoList.addElement(count); //Save previous list sizevisRectangle v = new visRectangle(x, y);drawings.addElement(v); //add new element to liststartRect = false; //done with this rectanglerect.setSelected(false); //unclick buttoncanvas.repaint();
}else
pickRect(x, y); //if not pressed look for rect to select}
58Software Quality Management
Java Memento Example (9/10)
It saves the previous position of a rectangle before moving it in a Memento:
public void rememberPosition() {
if (rectSelected){
Memento m = new Memento(selectedRectangle);undoList.addElement(m);
}}
59Software Quality Management
Java Memento Example (10/10)Undo operation
public void undo() {
if (undoList.size()>0) {//get last element in undo listObject obj = undoList.lastElement();undoList.removeElement(obj); //and remove it//if this is an Integer,//the last action was a new rectangleif (obj instanceof Integer) {
//remove last created rectangleObject drawObj = drawings.lastElement();drawings.removeElement(drawObj);
}//if this is a Memento, the last action was a moveif (obj instanceof Memento) { //get the Memento
Memento m = (Memento)obj;m.restore(); //and restore the old position
}repaint();
}}
60Software Quality Management
Visitor
Intent• Represent an operation to be performed on
the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates
61Software Quality Management
Motivation (1/4)
Example• Consider a compiler that represents programs
as abstract syntax trees• It will need to perform operations on abstract
syntax trees for "static semantic" analyses like checking that all variables are defined
• It will also need to generate code
62Software Quality Management
Motivation (2/4)
A bad solution…
63Software Quality Management
Motivation (3/4)
This last diagram shows part of the Node class hierarchyThe problem is that distributing all these operations across the various node classes leads to a system that is hard to understand, maintain, and changeIt will be confusing to have type-checking code mixed with pretty-printing code or flow analysis code
64Software Quality Management
Motivation (4/4)
65Software Quality Management
Applicability (1/2)Use the Visitor pattern when:• An object structure contains many classes of objects
with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes
• Many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them
66Software Quality Management
Applicability (2/2)
The classes defining the object structure rarely change, but you often want to define new operations over the structureChanging the object structure classes requires redefining the interface to all visitors, which is potentially costlyIf the object structure classes change often, then it is probably better to define the operations in those classes
67Software Quality Management
Structure
68Software Quality Management
Participants (1/3)Visitor (NodeVisitor) • 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.
• That lets the visitor determine the concrete class of the element being visited.
• Then the visitor can access the element directly through its particular interface
ConcreteVisitor (TypeCheckingVisitor) • implements each operation declared by Visitor. Each operation
implements a fragment of the algorithm defined for the corresponding class of object in the structure.
• ConcreteVisitor provides the context for the algorithm and stores its local state. This state often accumulates results during thetraversal of the structure
69Software Quality Management
Participants (2/3)
Element (Node)
• Defines an Accept operation that takes a visitor as an argument
ConcreteElement (AssignmentNode,VariableRefNode)
• Implements an Accept operation that takes a visitor as an argument
70Software Quality Management
Participants (3/3)
ObjectStructure (Program) • Can enumerate its elements. • May provide a high-level interface to allow the
visitor to visit its elements. • May either be a composite or a collection such
as a list or a set
71Software Quality Management
Collaborations (1/2)
A client that uses the Visitor pattern must create a ConcreteVisitor object and then traverse the object structure, visiting each element with the visitorWhen an element is visited, it calls the Visitor operation that corresponds to its class. The element supplies itself as an argument to this operation to let the visitor access its state, if necessary
72Software Quality Management
Collaborations (2/2)
The following interaction diagram illustrates the collaborations between an object structure, a visitor, and two elements:
73Software Quality Management
Consequences
Visitor makes adding new operations easy A visitor gathers related operations and separates unrelated ones Adding new ConcreteElement classes is hard Visiting across class hierarchies. Accumulating state Breaking encapsulation
74Software Quality Management
Visitor Example (1/5)
Consider a simple Employee object which maintains a record of the employee’s name, salary, vacation taken and number of sick days taken
75Software Quality Management
Visitor Example (2/5)Employee class
public class Employee {
int sickDays, vacDays;float Salary;String Name;
public Employee(String name, float salary,int vacdays, int sickdays) {vacDays = vacdays; sickDays = sickdays;Salary = salary; Name = name;
}public String getName() { return Name; }public int getSickdays() { return sickDays; }public int getVacDays() { return vacDays; }public float getSalary() { return Salary; }public void accept(Visitor v) { v.visit(this); }
}
76Software Quality Management
Visitor Example (3/5)
A basic abstract Visitor class is just:
public abstract class Visitor {
public abstract void visit(Employee emp);}
77Software Quality Management
Visitor Example (4/5)
The Visitor we are going to write first just sums the vacation data for all our employees:
public class VacationVisitor extends Visitor {
protected int total_days;public VacationVisitor() { total_days = 0; }
public void visit(Employee emp) {total_days += emp.getVacDays();
}
public int getTotalDays() {return total_days;
}}
78Software Quality Management
Visitor Example (5/5)
Now, all we have to do to compute the total vacation taken is to go through a list of the employees and visit each of them, and then ask the Visitor for the total:
VacationVisitor vac = new VacationVisitor();for (int i = 0; i < employees.length; i++) {
employees[i].accept(vac);}System.out.println(vac.getTotalDays());