Observer OOD Course S Karsenty Observer Define a
Observer OOD Course S. Karsenty
Observer • Define a one-to-many dependency between objects, so that changing one automatically updates others • For example, a spreadsheet and several charts of it are open • Changing data in a window should be immediately reflected in all 2
3
The Requirements • Document and Chart classes must not know each other, for reuse • Easily add new kinds of charts or other links • A dynamic number of charts 4
The Solution • Terminology – Subject and Observer – Publisher and Subscriber – Listeners • Subjects attach and detach listeners, and notify of events • Clients update themselves after receiving a notification 5
The Solution II • Here’s an abstract observer (interface or class): interface Observer { void update(); } • Concrete observers such as class Chart will implement. Observer 6
The Solution III • Here’s the (concrete) subject: class Subject { protected Array. List observers; } void attach(Observer o) { observers. add(o); } void detach(Observer o) { observers. remove(o); } void notify() { for (i in observers) do o. update(); } 7
The Solution IV • Both subject and observer will usually inherit from other classes as well • If multiple inheritance is not available, the observer must be a separate class that has a reference to the chart object and updates it • Java has a special mechanism – Inner classes – to make this easier 8
Observers as inner classes class A { public A(B b, C c) { b. add. Observer(new BObserver()); c. add. Observer(new CObserver()); } private class BObserver implements Observer { // Logic for updates on B in update method } } private class CObserver implements Observer { // Logic for updates on C in update method } 9
The UML 10
Participants : Subject • abstract class provides an interface for attaching and detaching observers. • Subject class also holds a private list of observers – Attach - Adds a new observer to the list of observers observing the subject. – Detach - Removes an existing observer from the list of observers observing the subject – Notify - Notifies each observer by calling the update() function in the observer, when a change occurs. 11
Participants: Concrete Subject • The class provides the state of interest to observers. It also sends a notification to all observers, by calling the notify() method in its superclass or base class (i. e, in the Subject class). – Get. State - Returns the state of the subject. 12
Participants: Observer • defines an updating interface for all observers, to receive update notification from the subject. The Observer class is used as an abstract class to implement concrete observers. Contains this function: – update() - An abstract function, to be overridden by concrete observers. 13
Participants: Concrete Observer • maintains a reference with the Concrete. Subject, to receive the state of the subject when a notification is received. Contains this function: – Update() - This is the overridden function in the concrete class. When this function is called by the subject, the Concrete. Observer calls the Get. State function of the subject to update the information it has about the subject's state. 14
/* File Name : Event. Source. java */ package obs; import java. util. Observable; import java. io. Buffered. Reader; import java. io. IOException; import java. io. Input. Stream. Reader; //Observable is here public class Event. Source extends Observable implements Runnable { public void run() { try { final Input. Stream. Reader isr = new Input. Stream. Reader( System. in ); final Buffered. Reader br = new Buffered. Reader( isr ); while( true ) { final String response = br. read. Line(); set. Changed(); notify. Observers( response ); } } catch (IOException e) { e. print. Stack. Trace(); } } } 15
/* File Name: Response. Handler. java */ package obs; import java. util. Observable; import java. util. Observer; /* this is Event Handler */ public class Response. Handler implements Observer { private String resp; public void update (Observable obj, Object arg) { if (arg instanceof String) { resp = (String) arg; System. out. println("n. Received Response: "+ resp ); } } } 16
/* Filename : myapp. java */ /* This is main program */ package obs; public class My. App { public static void main(String args[]) { System. out. println("Enter Text >"); // create an event source - reads from stdin final Event. Source ev. Src = new Event. Source(); // create an observer final Response. Handler resp. Handler = new Response. Handler(); // subscribe the observer to the event source ev. Src. add. Observer( resp. Handler ); // starts the event thread Thread thread = new Thread(ev. Src); thread. start(); } } 17
Applicability • When an abstraction has two aspects, one dependent on the other. Encapsulating these aspects in separate objects allows the programmer to vary and reuse them independently. (used when refactoring) • When a change to one object requires changing others, and it's not known in advance how many objects need to be changed. • When an object should be able to notify other objects without making assumptions about who these objects are. 18
Implementation Issues • Mapping subjects to their observers. – The simplest way for a subject to keep track of the observers it should notify is to store references to them explicitly in the subject. – However, such storage may be too expensive when there are many subjects and few observers. One solution is to trade space for time by using an associative look-up (e. g. , a hash table) to maintain the subject-to-observer mapping. Thus a subject with no observers does not incur storage overhead. On the other hand, this approach increases the cost of accessing the observers. 19
Implementation Issues • Observing more than one subject. – It might make sense in some situations for an observer to depend on more than one subject. For example, a spreadsheet may depend on more than one data source. – It's necessary to extend the Update interface in such cases to let the observer know which subject is sending the notification. – The subject can simply pass itself as a parameter in the Update operation, thereby letting the observer know which subject to examine. 20
Implementation Issues • Who triggers the update? • The subject and its observers rely on the notification mechanism to stay consistent. But what object actually calls Notify to trigger the update? Here are two options: – Have state-setting operations on Subject call Notify after they change the subject's state. • The advantage of this approach is that clients don't have to remember to call Notify on the subject. • The disadvantage is that several consecutive operations will cause several consecutive updates, which may be inefficient. – Make clients responsible for calling Notify at the right time. • The advantage here is that the client can wait to trigger the update until after a series of state changes has been made, thereby avoiding needless intermediate updates. • The disadvantage is that clients have an added responsibility to trigger the update. That makes errors more likely, since clients might forget to call Notify. 21
Implementation Issues • Dangling references to deleted subjects. • Deleting a subject should not produce dangling references in its observers. • One way to avoid dangling references is to make the subject notify its observers as it is deleted so that they can reset their reference to it. • In general, simply deleting the observers is not an option, because other objects may reference them, or they may be observing other subjects as well. 22
Implementation Issues • Making sure Subject state is self-consistent before notification. • To avoid calling unintentionally inherited operations that trigger updates when the subject is in an inconsistent state: • Have template methods in abstract Subject classes send notifications. • Define primitive operation for subclasses to override. • Make notify() the last operation in the template method • Document which Subject operations trigger notifications 23
Implementation Issues • Avoiding observer-specific update protocols : the push and pull models. • Often the subject broadcasts additional information about change. • The subject passes this information as an argument to update(). • The amount of information may vary widely • push model: the subject sends observers detailed information about the change. (observer less reusable) • pull model: the subject sends minimal notification, and the observers ask for details explicitly thereafter. (subject ignores observers, can be inefficient) 24
Implementation Issues • Specifying modifications of interest explicitly. • You can improve update efficiency by extending the subject's registration interface to allow registering observers only for specific events of interest. • When such an event occurs, the subject informs only those observers that have registered interest in that event. • One way to support this uses the notion of aspects for Subject objects. To register interest in particular events, observers are attached to their subjects using – void attach (Observer o, Aspect interest); where interest specifies the event of interest. At notification time, the subject supplies the changed aspect to its observers as a parameter to the Update operation. For example: void update(Subject s, Aspect interest); 25
Implementation Issues • Encapsulating complex update semantics. • When the dependency relationship between subjects and observers is particularly complex, an object that maintains these relationships might be required. • We call such an object a Change. Manager. • purpose is to minimize the work required to make observers reflect a change in their subject. E. g, if an operation involves changes to several interdependent subjects, you might have to ensure that their observers are notified only after all the subjects have been modified to avoid notifying observers more than once. (allso e. g. DAGChange. Manager: avoids redundant updates by handling directed-acyclic graphs of dependencies between subjects and their observers. ) • It maps a subject to its observers and provides an interface to maintain this mapping. • It defines a particular update strategy. • It updates all dependent observers at the request of a subject. 26
The Fine Print II • Who calls Notify? – Greedy – the subjects, on change – Lazy – the observers, on query • Common errors – Forgetting to detach an object when it is destroyed – Calling Notify in an inconsistent state • Java includes Observer as part of the standard libraries – In package java. util 27
Known Uses • All frameworks of all kinds – MFC, COM, Java, EJB, MVC, … • Handle user interface events • Handle asynchronous messages 28
Related Patterns • often associated with the model-viewcontroller (MVC) paradigm. In MVC, the observer pattern is used to create a loose coupling between the model and the view. Typically, a modification in the model triggers the notification of model observers which are actually the views. • (in a separate lecture) 29
The Model-View-Controller (MVC) architectural pattern Name MVC (Model-View-Controller) Description Separates presentation and interaction from the system data. The system is structured into three logical components that interact with each other. The Model component manages the system data and associated operations on that data. The View component defines and manages how the data is presented to the user. The Controller component manages user interaction (e. g. , key presses, mouse clicks, etc. ) and passes these interactions to the View and the Model. See Figure 6. 3. Example Figure 6. 4 shows the architecture of a web-based application system organized using the MVC pattern. Used when there are multiple ways to view and interact with data. Also used when the future requirements for interaction and presentation of data are unknown. Allows the data to change independently of its representation and vice versa. Supports presentation of the same data in different ways with changes made in one representation shown in all of them. Can involve additional code and code complexity when the data model and interactions are simple. When used Advantages Disadvantages 30
The organization of the Model-View. Controller 31
Web application architecture using the MVC pattern 32
MVC: aggregate design pattern • Model-View-Controller is not a Design Pattern itself, but is made up of a number of smaller design patterns. • The views form a tree using the Composite. Pattern. • The relationship between views and models is the Observer. Pattern. • The controllers are strategies of the views. • Document. View is more popular now than true Model. View. Controller, and it consists of Composite and Observer, but not Strategy. 33
Example : clock timer 34
Related Patterns • Mediator: By encapsulating complex update semantics, the Change. Manager acts as mediator between subjects and observers. • Singleton: The Changer. Manager may use the Singleton pattern to make it unique and globally accessible. 35
- Slides: 35