Practice Homework 1
CMSC 433
Programming Language Technologies and Paradigms
Fall 2003
The follow are exercises to get you familiar with writing design patterns.
We'll post answers to these exercises on Tuesday.
1 Iterator
BTree is a simple implementation of trees with arbitrary numbers of
children, where a value is stored at each node in the tree. Write a method
that returns an implementation of java.util.Iterator that returns
the value at each node using a pre-order traversal. Write another method
that returns an iterator doing post-order traversal instead.
2 Visitor
Expression is an abstract superclass for arithmetic expressions on
integers, where each expression can have up to two arguments. There are
various subclasses of this class, including Constant, for
representing integer constants; AddExpression, for representing the
sum of two expressions, etc.
Write two visitors for this class. The first will print out an expression,
and the second with compute its result. To do this, you will have to write
accept methods for each subclass of Expression, and write
two implementations of ExpressionVisitor, one for printing
expressions (called PrintVisitor), and one for computing
expressions (called ComputeVisitor). Each visitor should maintain
its own state that it accumulates while visiting. For printing, this will
be a string, while for computation this will be a integer, holding the
result of the computation. Each visitor will define a method
getResult that will return its state.
Try writing these visitors in two ways (you'll have to copy the code into
two separate directories). First, do internal traversal. That is,
have the accept method in each subclass of Expression
invoke the visitor on each of its children (if it has any). Second, do an
external traversal, within the visitor. In this case, the
accept method will simply call the visitor on itself, while the
calls to visit an Expression subclass's children will occur as part
of the visit method for that kind of expression. See the lecture
notes for more description on these two kinds of traversal.
3 Decorator
The StringGenerator interface has a single method
getString, which returns a String. One concrete
implementation of StringGenerator is ConstString, which
simply returns the same string each time it is called. Write two decorators
for StringGenerator. The first, called EscapeQuotes,
should, when its getString method is called, retrieve the string
s from the StringGenerator it decorates, and then create a new
string that is the result of replacing all occurrences of " in s
with \" instead. The second, called MakeBold, should wrap
prepend s with <b> and append to it </b>.
4 Singleton/Typesafe Enum
Create a type-safe enumeration class called Color that represents
the six colors red, blue, green, yellow, purple, and orange. Follow the
example for suits of cards given in the lecture notes, so that
Color instances have a toString method. (Question: do you
need to define a separate equals method? Why or why not?).
Think about adding a compareTo method having the signature
int compareTo(Color c), which could implement the following ordering:
red < blue < yellow < purple <
green < orange. In what ways might you do this? Think
about doing this by defining new subclasses to implement the colors, as
opposed to just keeping the class that you have.
5 Proxy
Create a proxy for StringGenerator objects described above, called
SecureGenerator. This class should have an extra method (that is,
in addition to the getString method) called void
authenticate(int key). By default, the SecureGenerator.getString
method always return the empty string "". However, if the user calls
authenticate with the ``magic number,'' then the proxy will from
then on delegate calls to getString to the object that it's a proxy
for.
Question: can you characterize the difference between a proxy and a
decorator?
6 Abstract Factory
Project 2 used abstract factory in the GraphFactory class. If you
wanted to make this factory potentially return multiple implementations of
Graph, how might you recode it? If you were to change it, assuming
that your JUnit tests used the factory, will they need to be modified?
7 State/Strategy
Look at the movie example from the refactoring lecture, and see how they
transform the switch statement for price codes to use the Strategy
pattern. In particular, define a Price interface which has a
single method double getPrice(int daysRented). Then implement
three subclasses of Price: RegularPrice,
NewPrice, and ChildrenPrice. Each one of these will
implement getPrice differently (look at the example for possible
equations). Then define a Movie class which has two fields, the
name of the movie, and the Price. Provide a get method for the
name, and get/set methods for the price. Finally, define a Rental
class with two fields, the Movie and the number of days it was
rented. This class will have a single method int amountFor() that
delegates its work to the Price of its Movie object.
Notice here that we have not ever used a switch statement---the
control comes from the decision of which Price object to initialize
our movie with. Moreover, we can change its price code later, if we wish,
using the set method. This is the key benefit of strategy: the algorithm is
not baked into the object, but can be switched at runtime.
Finally, is there ever a need to have more than one NewPrice,
ChildrenPrice, or RegularPrice object? How can you use
singleton to ensure that at most one of each is ever created?
8 Observer
You have already written an Observer, as explained in the class notes. Look
over your code, and understand why it implements this pattern.
This document was translated from LATEX by
HEVEA.