订阅者模式通常也成为发布-订阅模式,发布者也称为通知者,订阅者也称为观察者。通知者发出通知,各发布者则收到通知后做出相应的动作。由于存在不同的订阅者和通知者,所以将这两者抽象出来。
其实Subject和Observer是抽象类还是接口,这个是比较灵活的,取决于你的应用场景是怎样,总之就是要将它们抽象出来,方便不同的通知者和观察者来实现它们。
下面是代码实现。
首先是Subject抽象通知者。
1 package day_9_observer; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 /** 7 * 抽象通知者类 8 * @author turbo 9 * 10 * 2016年9月13日 11 */ 12 public abstract class Subject { 13 private List<Observer> observers = new ArrayList<Observer>(); 14 private String name; 15 16 public String getName() { 17 return name; 18 } 19 public void setName(String name) { 20 this.name = name; 21 } 22 public Subject(String name){ 23 this.name = name; 24 } 25 /** 26 * 新增观察者 27 * @param observer 28 */ 29 public void attach(Observer observer){ 30 observers.add(observer); 31 } 32 33 /** 34 * 移除观察者 35 * @param observer 36 */ 37 public void detach(Observer observer){ 38 observers.remove(observer); 39 } 40 41 /** 42 * 通知观察者 43 */ 44 public void notifyObservers(){ 45 for (Observer observer : observers){ 46 observer.update(); 47 } 48 } 49 }
接着是抽象观察者。
1 package day_9_observer; 2 3 /** 4 * 抽象订阅者 5 * @author turbo 6 * 7 * 2016年9月13日 8 */ 9 public abstract class Observer { 10 private String name; 11 private Subject subject; 12 13 public String getName() { 14 return name; 15 } 16 17 public void setName(String name) { 18 this.name = name; 19 } 20 21 public Subject getSubject() { 22 return subject; 23 } 24 25 public void setSubject(Subject subject) { 26 this.subject = subject; 27 } 28 29 public Observer(String name, Subject subject){ 30 this.name = name; 31 this.subject = subject; 32 } 33 34 public abstract void update(); 35 }
下面分别是具体的通知者和订阅者。
1 package day_9_observer; 2 3 /** 4 * 具体通知者 5 * @author turbo 6 * 7 * 2016年9月13日 8 */ 9 public class ConcreteSubject extends Subject { 10 /** 11 * @param name 12 */ 13 public ConcreteSubject(String name) { 14 super(name); 15 } 16 17 private String action; //这个在本例中并没有什么实际作用 18 19 public String getAction() { 20 return action; 21 } 22 23 public void setAction(String action) { 24 this.action = action; 25 } 26 27 }
1 package day_9_observer; 2 3 /** 4 * 具体观察者 5 * @author turbo 6 * 7 * 2016年9月13日 8 */ 9 public class ConcreteObserver extends Observer { 10 /** 11 * @param name 12 * @param subject 13 */ 14 public ConcreteObserver(String name, Subject subject) { 15 super(name, subject); 16 } 17 18 /* (non-Javadoc) 19 * @see day_9_observer.Observer#update() 20 */ 21 @Override 22 public void update() { 23 System.out.println(super.getName() + "收到" + super.getSubject().getName() + "的通知"); 24 } 25 26 }
客户端代码。
1 package day_9_observer; 2 3 /** 4 * 客户端 5 * @author turbo 6 * 7 * 2016年9月13日 8 */ 9 public class Main { 10 11 public static void main(String[] args){ 12 ConcreteSubject concreteSubject = new ConcreteSubject("通知者"); 13 ConcreteObserver observer = new ConcreteObserver("订阅者", concreteSubject); 14 15 concreteSubject.attach(observer); 16 concreteSubject.notifyObservers(); 17 } 18 }
输出结果:
这样我们就简单地完成了观察者模式。在《大话设计模式》中提到了,如果观察者是几个风马牛不相及的呢?我们现在是抽象成一个公共类,如果两个观察者无法抽象成一个公共类怎么办呢?《大话设计模式》中提到了利用“事件委托”来实现,由于此书是C#,但在Java中好像并没有线程的事件委托实现,在下一篇中会写利用“事件委托”来实现观察者模式,同样Java自带了Observer接口以提供对观察者模式的支持,下一篇我们也会利用JDK来实现观察者模式。