CS680 hw5 MVC TrainSet, Factory Methods, DI
Due Sunday, Oct. 26, files by midnight in UNIX
cs680/hw5 directory.
Study the supplied trainset project, from the solution
to hw2 (zip).
As you
know, it now has model and presentation packages, but still has some
non-MVC properties we can fix.
1. In hw2, we fixed the unwanted reference from TrainSet (model) to
TrainSystemGUI (GUI). However, as some noted, there was also a
reference from Train (model) to Accelerator (GUI), and it is still
there. First fix this. We want the Accelerator to set the train's speed
(in the model) at the appropriate time, when the user has finished
sliding the slider. Note the unused stateChanged method in Accelerator:
find out about this starting from the Sun Javadoc, and then put it to
use.
2. After 1., the only remaining interclass reference from model to GUI
involves the Animator. Fix this up following hw3's solution for Pong,
or your own observer treatment if you want.
3. Use cases. By playing with trainset, list its use cases, in
memo.txt.You can ignore the file commands. Then for each use case,
determine the code that executes on each initial user action. Define a
ControllerInterface, following the general form of F&F, p. 542,
but include a one-line comment on each action. List your interface in
memo.txt. Implement it in your project. Use it for actions in
TrainsetApp too.
4. In one case, the listener class is an inner class. Does it
need to be an inner class, or could it just as well be a nested class
(static inner class)?: explain the difference and the needs of this
class, in memo.txt.
5. Now we have separated out the controller code, so the rest of the
presentation code should be the view. The view should call no mutators
in the model. Is this true? Note that the startup code is not pure
view.
a. List the mutators (methods) for the model. Note that now the model
is all in its own package, so a search for public methods (including
static methods other than main) finds the model API.You can use the
eclipse class display in Package Explorer.
b. For each mutator, find its callers (list the classes that call it),
and determine any cases of view code calling a mutator.
c. Public constructors can change the state of things, although if the
constructed object is not connected to anything else, it's normally
harmless (or it's just confusing). In this system, what model objects
can be constructed by code outside the model package? Are any actually
constructed other than TrainSet?
d. Some getters allow the caller to change the model. For example,
List<TrainOnTrack> getAllTrains sounds dangerous: can't
the caller add a train to the list and change the TrainSet? Explain.
TrainSet.getTimer() returns a mutable object that is part of the model
state. Are there any other getters like this?
e. Based on these observations, do you have any suggestions for ways
to tighten up this model?
6. Finally, for real purity, we would like to get rid of the paint
methods, and the train color. Do this at least for the
Train/TrainOnTrack classes. Define a TrainDisplay class that represents
the GUI for an individual train-on-track, including its color and a
reference to its TrainOnTrack. There should be a list of these
TrainDisplay objects that the GUI uses for painting. Now we have claim
to pure MVC, right? Discuss any further deviations from MVC that you
see in memo.txt.
7. Factory methods. Refactor the current factory method for Layout into
a separate class LayoutFactory. Refactor it further so that
LayoutFactory is "closed" in the open/close sense, so that we could add
another type of Layout without editing LayoutFactory. Provide this
LayoutFactory to its using class, as you see in F&F, p. 116 for
PizzaFactory. This is an example of DI, dependency injection. In
memo.txt, explain why we don't want to absorb this LayoutFactory into
its using class, as the PizzaFactory was absorbed into PizzaStore in
F&F, p. 116-120. In other words, if we did so, what restriction
would ensue on Layouts for a particular TrainSet? What restriction is
there on PizzaStore of p. 120, for example, can a PizzaStore sell both
NYStyleCheesePizza and ChicagoStyleCheesePizza?
8. DI. We have seen how Pizza1 is built up from its components, bottom
up, using DI (dependency injection). Consider DI for TrainSet. Problem
7 has already set up DI for the LayoutFactory for TrainSet. What other
subcomponent of TrainSet is easily handled by DI? Discuss how to do it
in memo.txt. What about TrainOnTracks--discuss possible DI approaches.
Deliverables
We will collect your work electronically from a hw4
subdirectory
of the cs680 directory.
Your memo should be pure ascii text, with no markup (no html,
no MS
Word). When printed on the Department printers no text should be lost
at the ends of lines. If you want to submit some hard copy of diagrams,
you may bring them to class the day the assignment is due.
We will look in your cs680/hw4 directory.
It
should contain
- hw5/memo.txt (10 points)
- modified trainset project (20 points) in hw5/trainset, build.xml in hw5/trainset/build.xml, etc. It should have no
warnings
in eclipse (the supplied version has none) and should be formatted by
eclipse. You can do this for all sources at once by selecting them all
in Project Explorer and
right-click>>Source>>Format. Make
trainset display your name in the frame's title "Train Set modified by
..." so we can identify your program as it is running.
Some useful
info on public methods in model, in supplied project
C:\cs\cs680\trainset.soln\src\trainset\model>grep public
*.java|grep -v main|grep -v class|grep -v final|grep -v
toString
Note that some of the indented methods are in an inner class,
so they may not be really public
Animator.java:
public void actionPerformed(ActionEvent event) {
Animator.java:
public void setView(TrainSystemGUI view) {
CannotAttachException.java:
public String getMessage() {
CircularSegment.java:
public void paint(Graphics g) {
Curvature.java:
public int getSign() {
Curvature.java:
public boolean equals(Object obj) {
Curvature.java:
public int hashCode() {
DerailException.java:
public String getMessage() {
Direction.java:
public static Direction[] allDirections = { Direction.N, Direction.NW,
Direction.java:
public int getKey() {
Direction.java:
public Direction next() {
Direction.java:
public Direction previous() {
Direction.java:
public Direction reverse() {
Direction.java:
public Direction rotate() {
Direction.java:
public Direction rotate(int count) {
Layout.java:
public static Layout create(String layoutName, int width, int height,
int radius) {
Layout.java:
public List<Segment> getAllSegments() {
Layout.java:
public int getRadius() {
LayoutPoint.java:
public boolean closeEnough(LayoutPoint p) {
Segment.java:
public abstract void paint(Graphics g);
Segment.java:
public EndPoint() {
Segment.java:
public void setAttachedToA() {
Segment.java:
public void setAttachedToB() {
Segment.java:
public boolean isAttachedToA() {
Segment.java:
public boolean isAttachedToB() {
Segment.java:
public LayoutPoint getPoint() {
Segment.java:
public void setPoint(LayoutPoint point) {
Segment.java:
public Direction getDirection() {
Segment.java:
public void setDirection(Direction direction) {
Segment.java:
public Segment getNext() {
Segment.java:
public void setNext(Segment next) {
StraightSegment.java:
public void paint(Graphics g) {
Train.java:
public Train(Color color, int radius, int maxSpeed, int
accelerationRate) {
Train.java:
public Color getColor() {
Train.java:
public Accelerator getAccelerator() {
Train.java:
public void paint(Graphics g, int x, int y) {
TrainOnTrack.java:
public Train getTrain() {
TrainOnTrack.java:
public void paint(java.awt.Graphics g) {
TrainSet.java:
public TrainSet(int radius) {
TrainSet.java:
public void installLayout(Layout layout) {
TrainSet.java:
public List<TrainOnTrack> getAllTrains() {
TrainSet.java:
public void start() {
TrainSet.java:
public javax.swing.Timer getTimer() {
TrainSet.java:
public Animator getAnimator() {