Relevant LogicEvents vs Overriding |
||
|
Excerpts: Polymorphism: Purpose and Roles Examples projects:
|
Method Overriding vs Events ExampleNow, we will compare two versions of of the text processing example from Chapter 1, one using Events, the other using Overriding. There are two versions provided of this project: Example Project and Example Project-override. They are the same, except that the class extension is done using Events in the first one, and Method Overriding in the second. We will be revisiting these projects later, so we won't discuss all the details here. For now, we will look at how the code in the ProcessDisplayer class results in the display of the process results by the ProcessDisplayer subclasses.
The Events and Overriding versions of the project are the same; they only differ in how the relationship between ProcessDisplayer and its subclasses is established.
This lets us simplify our code: we can add as many more means of "displaying" our text processing results as we choose (web pages, remote applications on a network, other programs...), and just as long as we do so through a subclass of ProcessDisplayer, MainWindow doesn't have to be changed the tiniest bit.
Well, this is odd. There is in fact no code at all. There are two methods, but no code in them, and no Event Definitions. This works because classes both define an interface and carry the implementation. Only in this case, those two are split-the superclass defines the interface, but the subclass defines the implementation. This kind of empty method (called an abstract method) is very common when using method overriding. By putting these empty methods in ProcessDisplayer, we are saying that all subclasses can be treated as things with these methods on them. We rely on the subclass to override these methods and actually make them do something when they are called. The superclass defines the interface; the subclasses define the implementation.
Events vs Method OverridingThe results obtained in the two applications are the same, and there is actually a little less code in the method overriding example. Furthermore, method overriding lets a subclass modify any superclass method's behavior, not just act when an Event is called, which means it's more flexible. So it is probably unclear why Events are superior to Overriding. A general answer is this: one should put as much of a class's logic as possible as high in the class's inheritance chain as that logic can be. This is because the higher up some logic is, the more it is shared. Which in turn means that the important abstractions (which is just "hiding of details") in a good design are more toward the superclasses, not down among the subclasses. Similarly, it is always better to put the superclass in charge of the relationship between it and its subclasses. When the superclass is in charge of the relationship, we can more easily accommodate changes to shared behavior by just modifying code in the shared superclass, because the superclass can change the nature of its relationship to its subclasses with impunity. On the other hand, changing the relationship when the subclasses are in charge often means modifying all of the subclasses. Put this another way: if you define the relationship between the superclass and its subclasses in one place (the superclass), you can change that relationship by making changes in one place. But if the relationship is defined in the subclasses, you have to change all the subclasses to change the relationship. So using Events instead of method overriding leads to easier to maintain code. Also, Events are much clearer. Events are an explicit delegation mechanism. With Method Overriding, when and how a subclass should override superclass methods, and at what point it should call back up to the overridden method, must be documented separately (presumably, in a comment or note), and cannot be enforced. All of this is a bit abstract. Let's consider a practical example. Assume you're creating a program where you want to make all custom user interface controls, drawn in a canvas. You do this with method overriding, so you create a base class, MyControl, with a Paint method. The intention is that subclasses will override MyControl.Paint to actually draw themselves. Now, along comes the trend for "wet" looking user interfaces, and you decide you want to draw all your controls with a glow behind them (which must be drawn before the control draws its details) and a water drop effect (which must be drawn after the control draws its details). If you used method overriding, you're very sad, because you have a lot of work to do. The superclass has no way to guarantee itself an opportunity to act both before and after the subclass draws its details. You will have to rewrite the superclass and all of its subclasses. But if you used Events, you have no problem whatever. The superclass is in charge of when the subclass acts, and it is trivial to insert the required behavior both before and after the subclass's own drawing actions. Warning: include(end.php) [function.include]: failed to open stream: No such file or directory in /home/relevan/public_html/relevantlogic/oop-book/Events-v-Overriding.php on line 145 Warning: include() [function.include]: Failed opening 'end.php' for inclusion (include_path='.:/usr/lib/php:/usr/local/lib/php') in /home/relevan/public_html/relevantlogic/oop-book/Events-v-Overriding.php on line 145 |