设计模式之观察者模式

Posted 菜鸟_lch

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之观察者模式相关的知识,希望对你有一定的参考价值。

观察者模式,顾名思义需要两方,一方是被观察的(主题),另一方就是观察者。就拿直播间来说,直播间就相当于一个主题,而用户就是观察者,用户进入直播间就是向主题注册(加进了用户队列),一般来说,用户可以离开直播间(从主题中移除该用户),当然直播间的主播也可以将用户移出直播间(也相当于从主题中移除该用户)。也就是说其实主题和观察者的关系是一对多的关系,主题数据的变化,观察者能及时知道。

下面进行观察者模式的实现,首先是主题接口:

 1 package cn.liu.java.myjava.Interface;
 2 /**
 3  * 这是主题接口,主要作用是注册观察者,移除观察者还有就是通知观察者
 4  * 假设这里的应用场景是告知有当前注册的用户,现在有多少个观察者在监听
 5  * @author Administrator
 6  *
 7  */
 8 public interface Subject {
 9     //注册观察者
10     public void registerObserver(Observer observer);
11     //移除观察者
12     public void removeObserver(Observer observer);
13     //通知所有观察者
14     public void notifyObservers();
15 }

接下来是观察者接口:

 1 package cn.liu.java.myjava.Interface;
 2 /**
 3  * 观察者接口,该观察者主要是知道当前有多少个观察者注册了(相当于在线场景)
 4  * @author Administrator
 5  *
 6  */
 7 public interface Observer {
 8     //观察者被通知时候调用的方法
 9     public void show(int num);
10     //观察者主动注册
11     public void register();
12     //观察者主动取消订阅
13     public void remove();
14 }

接下来是主题接口的具体实现类:

 1 package cn.liu.java.myjava;
 2 
 3 import java.util.LinkedList;
 4 import java.util.List;
 5 
 6 import cn.liu.java.myjava.Interface.Observer;
 7 import cn.liu.java.myjava.Interface.Subject;
 8 
 9 /**
10  * 主题的实现类
11  * @author Administrator
12  *
13  */
14 public class SubjectImpl implements Subject{
15     //主题要通知观察者,那么必须在主题中注册观察者,用一个list来存储观察者。
16     //因为linkedlist的实现是使用了链表的实现方式,观察者模式经常需要增删用户,
17     //删除用户如果用链表就只需要调整指针,不需要移动后面的元素
18     private List<Observer> observers = new LinkedList<Observer>();
19 
20     public void registerObserver(Observer observer) {
21         // TODO Auto-generated method stub
22         observers.add(observer);
23         //添加了观察者就通知所有的观察者对象
24         notifyObservers();
25     }
26 
27     public void removeObserver(Observer observer) {
28         // TODO Auto-generated method stub
29         observers.remove(observer);
30         notifyObservers();
31     }
32     
33     public void notifyObservers() {
34         // TODO Auto-generated method stub
35         Observer observer = null;
36         for (int i = 0; i < observers.size(); i++) {
37             if ((observer = observers.get(i)) != null) {
38                 observer.show(observers.size());
39             }
40         }
41     }
42 
43     
44 }

最后就是观察者的具体实现:

package cn.liu.java.myjava;

import cn.liu.java.myjava.Interface.Observer;
import cn.liu.java.myjava.Interface.Subject;
/**
 * 观察者的实现
 * @author Administrator
 *
 */
public class ObserverImpl implements Observer{
    //观察者需要保留一个主题的引用,方便观察者的注册和移除
    private Subject subject;
    //为每个观察者给定一个名字
    private String name;
    public ObserverImpl(Subject subject , String name) {
        this.subject = subject;
        this.name = name;
    }
    public void show(int num) {
        // TODO Auto-generated method stub
        System.out.println(name+"收到通知:现在有"+num+"人注册了该服务");
    }
    public void register() {
        // TODO Auto-generated method stub
        subject.registerObserver(this);
    }
    public void remove() {
        // TODO Auto-generated method stub
        subject.removeObserver(this);
    }
    
}

接下来就是测试类:

 1 package cn.liu.java.myjava;
 2 
 3 import org.junit.Test;
 4 
 5 import cn.liu.java.myjava.Interface.Observer;
 6 import cn.liu.java.myjava.Interface.Subject;
 7 
 8 public class MyTest {
 9     @Test
10     public void testName() throws Exception {
11         Subject subject = new SubjectImpl();
12         Observer observer1 = new ObserverImpl(subject , "观察者一");
13         Observer observer2 = new ObserverImpl(subject , "观察者二");
14         Observer observer3 = new ObserverImpl(subject , "观察者三");
15         //观察者主动要求注册(其实其中的内部实现也是通过主题对象来注册)
16         subject.registerObserver(observer1);
17         //通过主题对象来注册
18         observer2.register();
19         observer3.register();
20         observer2.remove();
21         subject.removeObserver(observer3);
22         observer1.remove();
23         observer1.remove();
24     }
25 }

测试结果如图:

观察者模式基本实现就是这样了,java类库中也有观察者模式的具体接口,可以直接使用java类库来实现观察者模式,上述例子中不太好的就是由主题来进行各个观察者的通知,其实比较好的就是观察者可以主动到主题中抓取数据,这样可以方便不同的观察者按需来抓取需要的数据,减小主题的复杂性。

下面实现观察者主动去提取主题中的数据(size)

 1 package cn.liu.java.myjava.Interface;
 2 /**
 3  * 这是主题接口,主要作用是注册观察者,移除观察者还有就是通知观察者
 4  * 假设这里的应用场景是告知有当前注册的用户,现在有多少个观察者在监听
 5  * @author Administrator
 6  *
 7  */
 8 public interface Subject {
 9     //注册观察者
10     public void registerObserver(Observer observer);
11     //移除观察者
12     public void removeObserver(Observer observer);
13     //通知所有观察者
14     public void notifyObservers();
15 }
 1 package cn.liu.java.myjava.Interface;
 2 /**
 3  * 观察者接口,该观察者主要是知道当前有多少个观察者注册了(相当于在线场景)
 4  * @author Administrator
 5  *
 6  */
 7 public interface Observer {
 8     //观察者被通知时候调用的方法
 9     public void show();
10     //观察者主动注册
11     public void register();
12     //观察者主动取消订阅
13     public void remove();
14 }
 1 package cn.liu.java.myjava;
 2 
 3 import java.util.LinkedList;
 4 import java.util.List;
 5 
 6 import cn.liu.java.myjava.Interface.Observer;
 7 import cn.liu.java.myjava.Interface.Subject;
 8 
 9 /**
10  * 主题的实现类
11  * @author Administrator
12  *
13  */
14 public class SubjectImpl implements Subject{
15     //主题要通知观察者,那么必须在主题中注册观察者,用一个list来存储观察者。
16     //因为linkedlist的实现是使用了链表的实现方式,观察者模式经常需要增删用户,
17     //删除用户如果用链表就只需要调整指针,不需要移动后面的元素
18     private List<Observer> observers = new LinkedList<Observer>();
19     private int size;
20     public void registerObserver(Observer observer) {
21         // TODO Auto-generated method stub
22         observers.add(observer);
23         size = observers.size();
24         //添加了观察者就通知所有的观察者对象
25         notifyObservers();
26     }
27 
28     public void removeObserver(Observer observer) {
29         // TODO Auto-generated method stub
30         observers.remove(observer);
31         size = observers.size();
32         notifyObservers();
33     }
34     
35     public void notifyObservers() {
36         // TODO Auto-generated method stub
37         Observer observer = null;
38         for (int i = 0; i < observers.size(); i++) {
39             if ((observer = observers.get(i)) != null) {
40                 observer.show();
41             }
42         }
43     }
44 
45     public int getSize() {
46         return size;
47     }
48     
49     
50 }
 1 package cn.liu.java.myjava;
 2 
 3 import cn.liu.java.myjava.Interface.Observer;
 4 import cn.liu.java.myjava.Interface.Subject;
 5 /**
 6  * 观察者的实现
 7  * @author Administrator
 8  *
 9  */
10 public class ObserverImpl implements Observer{
11     //观察者需要保留一个主题的引用,方便观察者的注册和移除
12     private Subject subject;
13     //为每个观察者给定一个名字
14     private String name;
15     public ObserverImpl(Subject subject , String name) {
16         this.subject = subject;
17         this.name = name;
18     }
19     public void show() {
20         // TODO Auto-generated method stub
21         System.out.println(name+"收到通知:现在有"+((SubjectImpl)subject).getSize()+"人注册了该服务");
22     }
23     public void register() {
24         // TODO Auto-generated method stub
25         subject.registerObserver(this);
26     }
27     public void remove() {
28         // TODO Auto-generated method stub
29         subject.removeObserver(this);
30     }
31     
32 }

测试结果和第一个实现没区别,第二个只是不需要主题传递数据给观察者,观察者直接从主题提取需要的数据。

 

以上是关于设计模式之观察者模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 行为型模式 -- 观察者模式(发布-订阅(Publish/Subscribe)模式)

js设计模式之实现观察者模式实例代码

PHP设计模式之----观察者模式

PHP 设计模式之观察者模式

设计模式之观察者模式--PHP

设计模式之观察者模式2