< Day Day Up > |
19.1 Structure and ParticipantsThe delegation event model has three main participants:
An event is any predetermined occurrence that the event source considers significant enough to tell other objects about ”anything from the clicking of the mouse to the ending of a game to the submission of an order form. To notify an event listener of an event, the event source invokes an agreed-upon method on it. The event object is passed to the agreed-upon method by the event source, giving the event listener access to information about the event. In a minimal delegation event model implementation, the event source, event listeners, and event object participants break down into the classes and interfaces described in the following sections. 19.1.1 The Event SourceThe event source includes the following classes:
The EventListenerList class resides in the event package, but the event source class can reside in any package. The event source class has the following responsibilities:
For example, earlier we mentioned a hypothetical Chat class with two events, onChatMessage( ) and onUserNameChanged( ) . As an event source, instances of the Chat class would manage objects interested in receiving those events. At event time, a Chat class instance would invoke either onChatMessage( ) or onUserNameChanged( ) (as appropriate) on all registered listeners. In the former case, the Chat instance might send the chat message text using the messageText property of the event object. In the latter, it would send, perhaps, the old username and the new username using the oldUserName and newUserName properties of the event object. 19.1.2 The Event ObjectThe event object includes the following classes:
The EventObject class resides in the event package (along with the EventListenerList class), but the EventObject subclass can reside in any package. The event object describes an event. That is, the object stores information about the event in its properties, which it makes accessible either directly or via accessor methods. The event object also provides event listeners with a reference to the event source. In our Chat class example, the EventObject subclass might be called ChatEvent . It would define the following properties: messageText , messageSender , oldUserName , and newUserName . 19.1.3 The Event ListenerThe event listener includes (at least) two interfaces and one class:
The EventListener interface resides in the event package (along with the EventObject and EventListenerList classes), but the EventListener subinterface and class can reside in any package. The event listener class defines the methods that are invoked by the event source when events occur. The EventListener subinterface specifies the set of event methods that must be implemented by every event listener class. At event time, the event source invokes one of those methods on each listener object; each listener then has the opportunity to respond in some application-specific way. In our ongoing hypothetical Chat example, the EventListener interface might look like this: import event.EventListener; interface ChatListener extends EventListener { public function onChatMessage (e:ChatEvent):Void; public function onUserNameChanged (e:ChatEvent):Void; } Notice that the event object passed to each event method is a ChatEvent instance. One of the event listener classes in our Chat example might be ChatGUI , a class responsible for displaying the chat interface on screen. The ChatGUI class would implement both onChatMessage( ) and onUserNameChanged( ) . Here's a skeletal example of what the ChatGUI class might look like: class ChatGUI implements ChatListener { // Properties and methods used to render the interface not shown. // Constructor also not shown. public function onChatMessage (e:ChatEvent):Void { displayMessage(e.messageSender, e.messageText); } public function onUserNameChanged (e:ChatEvent):Void { updateUserList(e.oldUserName, e.newUserName); } } 19.1.4 Are Observer and Delegation Event Model Equivalent?Structurally, the delegation event model has much in common with the Observer pattern. The Observer pattern's two basic participants ”the subject class and the observer classes ” correspond to the delegation event model's event source class, which broadcasts events, and event listener classes, which receive event notifications. But are the two designs the same? Not exactly. The delegation event model is designed to broadcast specific, known events rather than generic updates. In Observer, the subject broadcasts updates to observers by invoking a generic update( ) method. But in the delegation event model, the event source broadcasts a specific type of event by invoking a custom method on its listeners. Listeners receiving the event must implement an interface that defines the method invoked by the event source. Furthermore, in the delegation event model, any class can broadcast events; the event source need not be a subclass of some base event-broadcasting class, such as Observable . The info object (which is optional in the Observer pattern) is formally required by the delegation event model, and its identity is known to both the event source and the event listeners. Finally, in Observer, the subject should broadcast an update only in response to a state change. Events, by contrast, can be broadcast for any reason deemed appropriate by the event source. Generally speaking, the Observer pattern works well as an internal update mechanism within a discrete system, such as maintaining the state of a single toggle button or a tile on a chessboard. In the preceding chapter, we saw Observer used effectively within the MVC pattern. Observer worked perfectly as a means of maintaining the internal state of our clock. By contrast, the delegation event model is typically appropriate when the granularity of events matters (i.e., when events should correspond to individual methods rather than a single update( ) method). Event granularity is desirable for event sources that have a wide variety of unknown event listeners, as is often the case for publicly distributed components . For example, a SliderBar component might use the delegation event model to broadcast onChanged( ) , onDragged( ) , and onReleased( ) events to the world, but internally, it might maintain its own visual appearance using Observer as part of MVC. |
< Day Day Up > |