This lab is a modified version of a lab originally developed at Rice University.
If you are working from home, you must once again download the new jar file named Classlibs.jar and place it in your
c:\projects\CSE115\Classlibs\Spring2006\folder.
Well, you've just turned in the Lab 5 and you may have noticed that while the last lab did solve the problem, it really wasn't very general. For instance, you should have noticed that writing your combination fish required you to duplicate some code due to Java's limitation of single inheritance. Further the last lab limited the behavior of a given fish. That is, a Chameleon fish was always a Chameleon fish. As a few people pointed out, "Why not just create classes to model the behavior of the fish and leave the fish class alone?" Well, ask and you shall receive.
Write an applet with 4 menus. The first menu allows the user to select a type of fish behavior, Regular, Chameleon, Dizzy, and Random Swim and then create fish of that type. The second menu allows the user to select any combination of Chameleon, Dizzy, or Random Swim and create a fish with that behavior.
The third menu allows the user to create a leader fish, and the fourth menu allows the user to create a follower fish. When a leader fish is created, it will take on the behavior currently specific by the MultiFish menu. When a fish with follower behavior is created, it will "follow" the leader on the screen. There will only be one fish with leader behavior allowed on the board at any one time. So the last leader created will be the leader that all of the follower fish must follow.
Additionally, when a fish is clicked by the user, it will become the new leader and take on the (composite) behavior specified by the MultiFish menu. That is, it will change its behavior while the program is running!
Before you start programming, look over the notes from the lectures. Very special (not-so) secret tip: review the Inheritance, Polymorphism and Interfaces lecture before beginning this assignment. If you don't understand something that is covered in that lecture, see your TA or instructor during their office hours.
Make sure you have read chapter 4, 5 & 6 of the Brown notes.
Get the Lab6
project skeleton from the LabSkeletons
repository and disconnect it from the repository.
Once again you are required to design your solution to
the lab. Create a file called Lab6.dia
in your project and submit
it with your jar file.
The assignment specification gives you a hint as to what classes you'll need. Recall the first step is to ask, what has already been written for me?
Once again, remember to design and code iteratively.
Many people make the mistake of thinking that objects can only represent data. However, objects are used to model concepts both tangible and intangible. It is important to remember that we can just as easily represent processes with objects as we can simple data. Once we free our minds from the self-imposed prison, we can begin programming at the correct level.
To quote from Gamma, Helm, Johnson and Vlissides' (known in the industry as "The Gang of Four") "bible", Design Patterns, Elements of Reusable Object-Oriented Software, design patterns
...are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.
A design pattern names, abstracts, and identifies the key aspects of a common design structure that make it useful for creating a reusable object-oriented design. The design pattern identifies the participating classes and instances, their roles and collaborations, and the distribution of responsibilities.
Design patterns are the biggest breakthrough in object-oriented design in the last twenty years and arguably the hottest area of modern OO research.
But design patterns are hardly just just a theoretical endeavor. Design patterns have their roots in industry, in the ways that programmers "in the trenches" have found through much trial and error to solve common design problems. Design patterns take these concrete solutions and abstract their behaviors and structure so that we can use them to understand and solve a wide variety of problems.
At the heart of a design pattern is often a UML diagram that shows the classes involved in the pattern.
We have already encountered the Observer-Observable pattern. In this lab we will discover the Strategy pattern, the Null pattern and the Decorator pattern.
The strategy design pattern is a way of abstracting behavior and capturing that behavior in an object. An embodiment of the classic tenent of separating the invariant and variant behaviors of a system, it enables one to break one's design into two parts:
The context deals with the strategies at the abstract strategy level. The abstract class contains an abstract method that that the context believes that it is executing. In actuality, at any given moment, the context is holding one of the concrete subclasses. Thus when the strategy's method is called, the resultant behavior is that of the concrete strategy being held.
The strategy pattern is one of the most fundamental and common design patterns and forms the basis for many other patterns. One is well advised to know it well.
The biggest benefits of the strategy pattern are
Classic scenarios where the strategy design is used are to change the language used in message windows depending on what country the program is being run in. Or changing the behavior of a button depending on what options had been previously selected. Netscape plug-ins are an example of a strategy pattern.
What did the different fish subclasses have in common? Each one's update method called the Fish class update method and then did something else, i.e.:
super.update(); // custom behavior here
The custom part can be left to separate classes, while the update can happen in our fish. If we are to allow another object to do the custom behavior for us, we need some way for our fish to tell it to do so. Further since there will be many different behaviors that are interchangeable the method signature needs to be the same for all of them.
Notice what we're talking about, we need an object that has some method,
and we don't care about what other methods it may have, nor what the real
class is. All we care is that is has some particular method. How do we write
this in Java? With an interface, of course! Create an interface in the Lab6
package. The interface will need a void method that takes a CSE115.FishBowl.Fish
.
Why? The behaviors must alter some part(s) of the fish, so they must have
some knowledge of the fish. Call the method anything you like.
Now create a new fish sub-class, that will model the idea of a fish with changeable behavior. Provide an instance variable inside whose type is the same as the interface you created above. You are dealing with the behavior polymorphically and this will allow you to set the behavior to any type of behavior the user wants. Now provide a mutator for the instance variable you just created.
Just a couple more steps and we'll be swimming right along. The fish class
must override the update()
method. In it you should call the
super-class' update()
method. After that call, place a call to
the instance variable's method, send along the fish as the parameter.
Finally, we need to give the instance variable a default value. What type of additional behavior did a regular fish have? Well actually it did nothing. But this doing nothing is just as valid as the other types of fish behaviors, so we'd better provide a class for it. Create a do nothing class that implements your interface. It's method (from the interface) should have an empty definition -- the true definition of doing nothing. The class you just created is an example of the Null Object design pattern. While it was omitted from the Gang of Four book, it is incredibly important and powerful. It allows us to give to represent nothingness in our system in the same way we are representing doing something.
This is probably a good time to test things out. Once you know this works, you can write your other behavior classes and hook them up in your class that is used by the Single Fish menu.
Now let's consider having composite behaviors, just like in our combination fish in the last lab. In that case, what you had was a fish with 2 behaviors. You can easily create a class, that knows 2 of your interface objects. Since it is a behavior it implements the interface as well. It's method simply calls the method of both behaviors it knows. This is called the Decorator pattern. Getting this class working is the key to making the Multi Fish menus work. The TAs will discuss in recitation how to leverage this pattern to make the menu work fully.
There is a switch to the behavior of the leader and follower fish for this lab. We also need to correct a problem that was present in Lab 5 if you looked for it.
First, let's work on the problem of creating a leader fish. When "Make it" is selected for the leader fish, it needs to find out what the behavior is from the Multi-Behavior menu. However, how do we get the behavior from the Multi-Behavior menu? This questions is a bit dicey. Remember the user can change the selections in the Multi Fish menu at any time, so the fish will need to check with the class that knows about the menu clicks. A different class creates the leader fish than controls the multi-menu. Well, it's easy then, just make the class that implements the LeaderFollowerFishBehaviorMenuObserver know the object that implements the MultiBehaviorMenuObserver.
Wait a minute, though! That object creates the leader/follower fish, but a different object creates the fish with multiple behaviors, and another totally different object created fish with singular behaviors. The user is allowed to click on any type of fish to give it the multiple behaviors. Ick!
Recall that instance variables are unique to each object. However, we can
take an instance variable declaration and make it into a class variable
using the keyword static
. Static variables are shared among all
instances of some class. That means, that if our fish class had a class
variable of the type of object that implements the MultiBehaviorMenuObserver,
they could then ask that object for the current composite behavior.
So then how will we be able to ask the object that handles the Multi
menu about the current composite behavior? By creating a static accessor.
Write a regular accessor, but include static
before the return
type. This now allows you to call the method on the class rather than on an
object. So, once you've created your Multi menu handler, just call
the static accessor through the class. The TAs will go over this.
OK - so a leader fish can be created with the proper behavior. Each of the fish need to know who the leader is. This is easy, you did this in the last lab. However, there is one small change this time. This time, there is only one leader fish and that leader fish could change during the life of the program. In Lab 5, the leader for a particular follower fish never changed. Therefore, we need an object that could keep track of (or hold) the current leader. We have already seen an object that does this functionality in Lab 4 - use a holder again for the leader fish. When a new leader is created, the holder should be told and each of the follower fish should know the holder to ask who its leader is.
There is one more problem left over from Lab 5. In lab 5, if you created a follower fish without a leader fish, the entire program crashes (ie - stops working). We need to fix this, but how? Well, the easiest thing to do is re-use an idea we have seen already this lab. Before the first leader is created, the holder holds onto a null leader. If a follower fish is created before the first leader, the null leader fish will tell the follower to always go to the same location in the tank. After a leader is created, the follower will follow the leader.
FishBowl
and
FishBowl.Strategy
packages in Javadoc format. Also of interest is
the NGP.Utilities
class.
Once you are ready to submit, export your solution as a jar file, just as you did in previous labs, but name your jar file Lab6.jar
Use the electronic submission program that corresponds to your recitation. For further directions on the submission program, please refer back to the earlier labs.
Due 11:59:59pm the day before your recitation meets the week of March 27th, 2006.