设计模式之观察者模式
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 }
测试结果和第一个实现没区别,第二个只是不需要主题传递数据给观察者,观察者直接从主题提取需要的数据。
以上是关于设计模式之观察者模式的主要内容,如果未能解决你的问题,请参考以下文章