CHAPTER 2

image

Observer Patterns

GoF Definition: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Concept

In this pattern, there are many observers (objects) which are observing a particular subject (object). Observers are basically interested and want to be notified when there is a change made inside that subject. So, they register themselves to that subject. When they lose interest in the subject they simply unregister from the subject. Sometimes this model is also referred to as the Publisher-Subscriber model.

Real-Life Example

We can think about a celebrity who has many fans. Each of these fans wants to get all the latest updates of his/her favorite celebrity. So, he/she can follow the celebrity as long as his/her interest persists. When he loses interest, he simply stops following that celebrity. Here we can think of the fan as an observer and the celebrity as a subject.

Computer World Example

In the world of computer science, consider a simple UI-based example, where this UI is connected with some database (or business logic). A user can execute some query through that UI and after searching the database, the result is reflected back in the UI. In most of the cases we segregate the UI with the database. If a change occurs in the database, the UI should be notified so that it can update its display according to the change.

Illustration

Now let us directly enter into our simple example. Here I have created one observer (though you can create more) and one subject. The subject maintains a list for all of its observers (though here we have only one for simplicity). Our observer here wants to be notified when the flag value changes in the subject. With the output, you will discover that the observer is getting the notifications when the flag value changed to 5 or 25. But there is no notification when the flag value changed to 50 because by this time the observer has unregistered himself from the subject.

UML Class Diagram

9781484218013_unFig02-01.jpg

Package Explorer view

High-level structure of the parts of the program is as follows:

9781484218013_unFig02-02.jpg

Implementation

package observer.pattern.demo;
import java.util.*;

class Observer
    {
        public void update()
        {
                System.out.println("flag value changed in Subject");
        }
    }

    interface ISubject
    {
        void register(Observer o);
        void unregister( Observer o);
        void notifyObservers();
    }
    class Subject implements ISubject
    {
        List<Observer> observerList = new ArrayList<Observer>();
        private int _flag;
        public int getFlag()
        {
           return _flag;
        }
        public void setFlag(int _flag)
        {
          this._flag=_flag;
          //flag value changed .So notify observer(s)
                 notifyObservers();
        }
        @Override
        public void register(Observer o)
        {
            observerList.add(o);
        }
        @Override
        public void unregister(Observer o)
        {
            observerList.remove(o);
        }
        @Override
        public void notifyObservers()
        {
           for(int i=0;i<observerList.size();i++)
                {
                    observerList.get(i).update();
                }
        }
    }
class  ObserverPatternEx
{
        public static void main(String[] args)
    {
                System.out.println("***Observer Pattern Demo*** ");
        Observer o1 = new Observer();
        Subject sub1 = new Subject();
        sub1.register(o1);
        System.out.println("Setting Flag = 5 ");
        sub1.setFlag(5);
        System.out.println("Setting Flag = 25 ");
        sub1.setFlag(25);
        sub1.unregister(o1);
        //No notification this time to o1 .Since it is unregistered.
        System.out.println("Setting Flag = 50 ");
        sub1.setFlag(50);
    }
}

Output

9781484218013_unFig02-03.jpg

Note

The above example is one of the simple illustrations for this pattern. Let us consider a relatively complex problem. Let us assume the following:

  1. Now we need to have a multiple observer class.
  2. And we also want to know about the exact change in the subject. If you notice our earlier implementation, you can easily understand that there we are getting some kind of notification but our observer does not know about the changed value in the subject

Obviously now we need to make some change in the above implementation. Note that now we cannot use concrete observers like the following:

List<Observer> observerList = new ArrayList<Observer>();

Instead we need to use :

List<IObserver> observersList=new ArrayList<IObserver>();

And so we need to replace Observer with IObserver in corresponding places also. We have also modified our update function to see the changed values in the Observers themselves.

UML Class Diagram

9781484218013_unFig02-04.jpg

Package Explorer view

High-level structure of the parts of the modified program is as follows:

9781484218013_unFig02-05.jpg

Implementation

package observer.pattern.demo2;
import java.util.*;

    interface IObserver
    {
        void update(int i);
    }
    class Observer1 implements IObserver
    {
        @Override
                public void update(int i)
                {
                System.out.println("Observer1: myValue in Subject is now: "+i);
                }
    }
    class Observer2 implements IObserver
    {
        @Override
                public void update(int i)
                {
                        System.out.println("Observer2: observes ->myValue is changed in Subject to :"+i);
                }
    }

    interface ISubject
    {
        void register(IObserver o);
        void unregister(IObserver o);
        void notifyObservers(int i);
    }

    class Subject implements ISubject
    {
        private int myValue;

        public int getMyValue() {
                        return myValue;
                }

                public void setMyValue(int myValue) {
                        this.myValue = myValue;
                         //Notify observers
                        notifyObservers(myValue);
                }

                List<IObserver> observersList=new ArrayList<IObserver>();

                @Override
        public void register(IObserver o)
        {
                observersList.add(o);
        }
                @Override
        public void unregister(IObserver o)
        {
                observersList.remove(o);
        }
        @Override
        public void notifyObservers(int updatedValue)
        {
           for(int i=0;i<observersList.size();i++)
                {
                        observersList.get(i).update(updatedValue);
                }
        }
    }

    class ObserverPatternModifiedEx
    {
        public static void main(String[] args)
        {
                System.out.println("*** Modified Observer Pattern Demo*** ");
            Subject sub = new Subject();
            Observer1 ob1 = new Observer1();
            Observer2 ob2 = new Observer2();

            sub.register(ob1);
            sub.register(ob2);

            sub.setMyValue(5);
            System.out.println();
            sub.setMyValue(25);
            System.out.println();

            //unregister ob1 only
            sub.unregister(ob1);
            //Now only ob2 will observe the change
            sub.setMyValue(100);
        }
    }

Output

9781484218013_unFig02-06.jpg

Assignment

Implement an observer pattern where you have multiple observers and multiple subjects.

Image Note  I always suggests that you do the assignments by yourself. Once you complete your task, come back here to match the output.

UML Class Diagram

9781484218013_unFig02-07.jpg

Implementation

package observer.pattern.demo3;

import java.util.*;

    interface IObserver
    {
        void update(String s,int i);
    }
    class Observer1 implements IObserver
    {
        @Override
                public void update(String s,int i)
                {
                System.out.println("Observer1: myValue in "+ s+ " is now: "+i);
                }
    }
    class Observer2 implements IObserver
    {
        @Override
                public void update(String s,int i)
                {
                        System.out.println("Observer2: observes ->myValue is changed in "+s+" to :"+i);
                }
    }
    class Observer3 implements IObserver
    {
        @Override
                public void update(String s,int i)
                {
                        System.out.println("Observer3 is observing:myValue is changed in "+s+" to :"+i);
                }
    }

    interface ISubject
    {
        void register(IObserver o);
        void unregister(IObserver o);
        void notifyObservers(int i);
    }

    class Subject1 implements ISubject
    {
        private int myValue;

        public int getMyValue() {
                        return myValue;
                }

                public void setMyValue(int myValue) {
                        this.myValue = myValue;
                         //Notify observers
                        notifyObservers(myValue);
                }

                List<IObserver> observersList=new ArrayList<IObserver>();

                @Override
        public void register(IObserver o)
        {
                observersList.add(o);
        }
                @Override
        public void unregister(IObserver o)
        {
                observersList.remove(o);
        }
        @Override
        public void notifyObservers(int updatedValue)
        {
           for(int i=0;i<observersList.size();i++)
                {
                        observersList.get(i).update(this.getClass().getSimpleName(),updatedValue);
                }
        }
    }
    class Subject2 implements ISubject
    {
        private int myValue;

        public int getMyValue() {
                        return myValue;
                }

                public void setMyValue(int myValue) {
                        this.myValue = myValue;
                         //Notify observers
                        notifyObservers(myValue);
                }

                List<IObserver> observersList=new ArrayList<IObserver>();

                @Override
        public void register(IObserver o)
        {
                observersList.add(o);
        }
                @Override
        public void unregister(IObserver o)
        {
                observersList.remove(o);
        }
        @Override
        public void notifyObservers(int updatedValue)
        {
           for(int i=0;i<observersList.size();i++)
                {
                        observersList.get(i).update(this.getClass().getSimpleName(),updatedValue);
                }
        }
    }

    class ObserverPatternDemo3Ex
    {
        public static void main(String[] args)
        {
                System.out.println("*** Observer Pattern Demo3*** ");
            Subject1 sub1 = new Subject1();
            Subject2 sub2 = new Subject2();

            Observer1 ob1 = new Observer1();
            Observer2 ob2 = new Observer2();
            Observer3 ob3 = new Observer3();

          //Observer1 and Observer2 registers to //Subject 1
            sub1.register(ob1);
            sub1.register(ob2);
          //Observer2 and Observer3 registers to //Subject 2
            sub2.register(ob2);
            sub2.register(ob3);
          //Set new value to Subject 1
          //Observer1 and Observer2 get //notification
            sub1.setMyValue(50);
            System.out.println();
          //Set new value to Subject 2
          //Observer2 and Observer3 get //notification
            sub2.setMyValue(250);
            System.out.println();
            //unregister Observer2 from Subject 1
            sub1.unregister(ob2);
          //Set new value to Subject & only //Observer1 is notified
            sub1.setMyValue(550);
            System.out.println();
            //ob2 can still notice change in //Subject 2
            sub2.setMyValue(750);

        }
    }

Output

9781484218013_unFig02-08.jpg
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.179.225