Goal:
Liskov: Factories and flyweights.
Reconsider the immutable stack abstraction in assignment 3. A naive solution generates a new stack object on every call to a constructor or a producer. In addition, the call to the constructor ensures a dependency between clients and the stack class. To overcome these drawbacks, make the following changes:
IStack
with three methods, push(), pop(),
and top().
FlyStack that implements the
immutable IStack abstraction:
public class FlyStack implements IStack {...}
final private Object topValue; // Top of the stack
final private FlyStack previous; // Rest of stack
// holds all existing Stacks = (x, this) generated by this.push(x)
final private Map<Object, FlyStack> m;
private final static IStack emptyStack = new FlyStack(null, null);
private FlyStack (Object top, FlyStack predecessor) {
topValue = top;
previous = predecessor;
m = new HashMap<Object, FlyStack>();
}
Do not provide any additional constructors or add any
other representation variables - either at the object or
at the class level.
The idea with m is that if a stack object has
been created previously with x on top
of this,
then Map m will have an entry in it of the
form
(x, FlyStack with topValue=x and remainder=this)
As a result, each different stack will only be created once.
This includes the empty stack, which is the rationale for
the static emptyStack variable.
makeStack() to FlyStack.
public static IStack makeStack() { ... }
equals()
and hashCode(). If so, override them.
If not, explain why not.
toString() in the usual way.
Possible Bonus Points:
FlyStack is not threadsafe.
Explain why not, and fix it. (1 point.)
FlyStack is not generic.
Fix it. (1 point.)