COMP 310
|
Lec10: Collisions, killing and the environment |
![]() ![]() ![]() ![]() |
Homework should be completed before class on Friday. Directions on how to use Subclipse to turn in your work will be posted, but we will spend some class time on Friday to make sure that everyone is able to do it successfully. Bring your laptops to class!
How do you get a ball to react to the collision, e.g. change color, explode, get killed, etc? Is this a variant or invariant behavior?
Once again, we see the subtle line between the invariance of doing something vs. the variance of what is being done.
Invariantly, we need a method on the ball to perform the post-collision behavior.
Variantly, we need some sort of strategy to actually perform that behavior.
The collision handling command from the previous lecture is therefore forced to call the invariant method of the ball for post-collision behavior. That method in turn, must then delegate to a strategy to handle it. (Why shouldn't the strategy's collision update method be called directly from the collision command?)
Since classes are collections of lambdas (methods), then the update strategy can carry methods for both updating the state and post-collision updating.
Likewise what happens when one attempts to kill a ball?
Should a ball be able to react to such an action?
Is the attempt to kill a ball necessarily successful?
This is basically a very similar issue to the post-collision behaviors, so we would expect a very similar solution, i.e. an invariant method calling variant behaviors on a strategy. The update strategy class at this point, is now up to 3 different update methods: update state, update collision, update kill.
But what about the issue of a potentially non-successful kill attempt? When a ball's "kill" method is called, does it invariantly get removed from the dispatcher?
This means that the method that invariantly kills the ball cannot be the same method as being called for the kill attempt -- there are two different methods, e.g. "kill" and "killSelf".
This technique of "intercepting" calls is very common and we will see it again in various forms, though all involve some sort of "indirection" layer that is being inserted into the program flow or architecture.
While it is tempting to simply give each ball a reference to the main model class, in general, this would be a very unwise solution as this would expose way too much of the inner workings of the model to the ball.
Restrict the visibility of the model by using an interface. At this point the ball only needs the following services from the model:
Accessor for the dispatcher
Accessor for the animation canvas, or perhaps only just its width and height.
These services should be methods on an interface, IEnvironment, that represents the enivironment in which the ball is operating.
Two ways of accomplishing this:
The model implements IEnvironment
Pros: Easy to implement. Minimum of layers to slow the code down.
Cons: Less flexible. Model cannot implement any other interface as well.
The model has a factory method that returns an IEnvironmentimplementation.
Pros: Much more flexible. Allows model to simulataneously implement multiple interfaces. Clearly disambiguates the notion of a balls environment from the model itself.
Cons: More difficult (not much) to implement. Adds another layer of code that reduces speed. Has higher memory requirements because of added objects, though in general, the number of objects made is very small and can be managed, e.g. to give the same environment object to every ball rather than instantiating a new one each time.
The bottom line here is using an interface to protect (encapsulate) the system by providing a portal with limited capabilities. From a security standpoint, this helps seal off the system from posible intrusion.
Solution to the problem of how a single class can implement more than one interface or the same interface with different behaviors:
The factory method technique above is also the solution to enabling classes to implement more than one interface at the same time, in spite of Java's single inheritance restriction. The class simply needs to have multiple factory methods, each producing its own implementation of a particular interface.
This even enables the class to implement the same interface multiple times but with different behaviors--each factory method, while returning a result of the same type, is producing implementations of that same interface but with different behaviors. This is possible because technically, the factory methods are producing separate objects.
© 2010 by Stephen Wong