Relevant Logic icon

Relevant Logic


Events vs Overriding

Method Overriding vs Events Example

Now, 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.

  1. Open Example Project. If you haven't recently, run it, so you can see what it does.

  2. Open the ProcessDisplayer class. Examine the Display method. Notice that it just passes the call down to its subclass in the corresponding Display Event.

  3. Open each of the subclasses of ProcessDisplayer: ClipboardDisplay, EditFieldDisplay, ListBoxDisplay and FileDisplay, and examine each class's Display Event Handler. Note how they are able to take the ProcessResult object passed to them, and "display" the results in very different ways.

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.

  1. The logic of all of this employs the very essence of polymorphism: MainWindow is able to ignore what each ProcessDisplayer subclass does, and just ask it to do its thing.

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.

  1. Let's now look at how the same thing is done with Method Overriding. Open Example Project-override, and look at the code in ProcessDisplayer.

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.

  1. Look now at the subclasses. Each has implementations for the same two methods Remember: since these methods have the same signatures as the methods on ProcessDisplayer, these will be the methods that are actually executed in preference to the empty methods on ProcessDisplayer.

Events vs Method Overriding

The 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