The purpose of this section of the Journal is to illustrate how I changed my initial design into my final design.
ANALYSIS OF FIRST DESIGN:
Before I attacked the design problems of my first run at the program I decided to make my OMT design as detailed as possible. I went back to my last OMT diagram and rearranged subsystems, added all of the GP superclasses that had been assumed before, color coded different parts of my system -- in general I just cleaned it up. In the following diagrams classes which are colored red are part of GP. Classes which are colored green are part of the cs015.SP package. Classes which are colored blue are top-level objects which comprise a smaller subsytem which have their own diagram. Classes which are colored black (obviously can't do a neat color tag here!) are classes I have no written yet. Finally, all classes which remain white are classes which I have created on my own.
- Top-level OMT design diagram
InputChooser
subsytem OMT design diagramShipChooser
subsytem OMT design diagramThis proved to be a very useful idea as it allowed be to even better understand the system I had created. In the analysis of my first design here were the problems/improvements I came upon:
- The code for the
ShipBehavior
and theWeaponBehavior
classes was exaclty the same. These two classes should be able to be factored into one class that can manipulate both. In order to do this I will need to setup an interface which bothShip
s andWeapon
s can implement.
- The code inside of the subclasses of
Key
andMouse
also do everything the same. This code too should be able to be factored out. To solve this problem I am going to createShipManipulator
objects which encapsulate one specific action which can be executed upon a ship. As well as factoring code out of theKey
andMouse
subclasses it will allow me to do away with them all together. I will only need one generic class which accepts aShipManipulator
and executes it whenever it is activated. As a side note there exists an interface in GP called aGP.Doable
. This class will give me this functionality exactly. I am going to use it.
- The way I was using the
GP.Components.ColorChooser
was entirely wrong. I need to subclass off of this class in order to affect theShip
's color. This will be quite simple and should fix my current bug.
- I kind of felt that it was tedious for me to always have to be getting the reference to the
Ship
whenever I wanted to do something. Also, what happened if the reference to theShip
was null? I had no guarantee that I would always be getting a valid reference back when I calledGetShip()
on theShipHolder
. In order to fix this I decided to use a pattern I had heard one of my TAs talking about, the Proxy pattern. This pattern allows me to forward messages (method calls) off to an object and to let it worry about what to do. This seemed to fit in with the Delegation pattern we had always been told we were using so it sounded good to me. Now I could let theShipProxy
worry about whether or not it had a valid reference or not and I could just call methods on it.However there was one issue. A
ShipProxy
is not aShip
. So if I want to treat it like aShip
what can I do? The TAs told me I could create an interface that consisted of all the methods I wanted to call on aShip
. Then, bothShip
andShipProxy
could implement them and I could pass messages anytime that I pleased.
- I also realized that as standing, I had a toggle button containing a row of buttons. This was happening in my
MouseSelect
andMouseController
classes. Eventhough tis class wasn't graphically containing these classes it was modelling a containment relationship instead of the appropriate association relationship. To fix this error I made theSimulation
class contain theMouseController
and pass it as a parameter toInputChooser
so thatInputChooser
could pass a reference on toMouseSelect
.
- Another thing I decided to do was to make subpackages. When looking through my code I saw that I had a good amount of classes and that it might be nice if I created some more organization for them. For example my
ShipManipulator
s could all be in one package, as could all of myShip
subclasses.
NEW DESIGN:
As I started to code up my new design I realized that my ship was still not moving at all. The only thing it could do is
- Top-level OMT design diagram
InputChooser
subsytem OMT design diagramShipChooser
subsytem OMT design diagramShipManipulator
subsytem OMT design diagramActivate
. I decided to look into the problem. So I thre in someSystem.out.println
s to tell me if the ship was actually receiving the messages. It was. So what could the problem be? Aha! I realized that I hadn't set any default values in myAttacker
subclass to govern how it moved.After I set the initial values I recompiled and voila, it worked! Fantastic I thought. Time to move on. But all things were still not 100% up to spec. I still had not implemented the
Explorer
. Understanding that it should be easy to write, by definition, I decided to code it up.And it worked as expected, but with one drawback. When I went to switch between the different ships the old one stayed on the screen. This was an easy fix. Eventhough I was "losing" my reference to the old ship GP was not. All I would have to do is
Hide()
it. This worked well.A realization I made was that subclassing off of
GP.Components.ColorChooser
was the wrong thing to do. I didn't need to specialize at all. All I had to do was set the color of theShipProxy
to be aGP.Attributes.Colors.Chooser
that was tied to theGP.Components.ColorChooser
. But this didn't entirely work properly. Once I changed the ship the new ship was no longer tied to the color chooser! So to maintain persistance I added some code to theSetShip()
method of theShipProxy
class that set the color of the new ship. This did indeed work.Another problem I had was that I had made the
Light
for theExplorer
a triangle. It looked terrible. So I modified this code so that it would project a a circle of light around theExplorer
ship (whough the code doesn't care what kind of ship it is).But this was a bit difficult because I wanted to have the light shine for a brief period of time and then die. After studying
GP.Behaviors.Perpetual
for awhile I decided that I could use the parameterdouble time
that is passed in throughApply
to count how long the behavior had been running for. Once it had run longer than the specified duration I would destroy the light and remove the behavior. Testing this out proved it to be a successful idea. I did, however, have to write a new behavior class calledLightBehavior
to handle the extra code.By now my code was fully functional and it was time to continue to clean it up and make it look pretty. Here is my revised design and code for the end of my second run:
Design Diagrams and Code: