初探观察者模式
观察者模式:定义了对象之间一对多的依赖,当一个对象改变状态时,他的所有依赖都会收到通知并自动更新。
场景:有这样一个需求,风险监控的时候,某个用户关注了某个信息,并且希望这个信息有重大变动的时候能够往邮箱、手机、当前用户登录的网页发送这个信息。
让我们来看看根据需求马上动手的代码:
1、定义发送信息的类
package pattern.observer; public class SendEmail { public void show(String message){ System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱"); } } public class SendPhone { public void show(String message){ System.out.println("您在XXX订阅的信息有更新,更新内容:"+message + "。该信息来自XXXX"); } } public class SendWeb { public void show(String message){ System.out.println("您订阅的信息有更新,更新内容:"+message); } }
2、获取改变的信息并发送
public void messageChange(String message){ SendEmail sendEmail = new SendEmail(); SendPhone sendPhone = new SendPhone(); SendWeb sendWeb = new SendWeb(); sendEmail.show(message); sendPhone.show(message); sendWeb.show(message); }
我们来分析一下这样写代码的不足:首先,发送信息类里面的show()方法看起来像一个统一的接口,我们可以封装起来;其次,针对具体实现变成,这样会导致我们增加或删除一个发送通知的类时,我们必须要修改实现类。
接下来,我们分析一下观察者模式是怎么实现对象一对多的情况的。
首先实现主题接口和观察者接口
package pattern.observer; public interface Subject { //注册观察者(就是发送信息的类) public void registerObserver(Observer observer); //删除观察者 public void removeObserver(Observer observer); //通知观察者信息已经改变 public void notifyObservers(); } public interface Observer { //观察者接口,一旦信息有改变,执行更新操作 public void update(String message); }
然后信息实现主题(Object)接口
package pattern.observer; import java.util.ArrayList; public class Message implements Subject{ private String message; private ArrayList observers; public Message(){ observers = new ArrayList(); } //一旦信息符合要求,通知观察者更新信息 public void messageChange(){ if(message.equals("重大变化")){ notifyObservers(); } } //有信息进来就调用信息改变的方法 public void setMessage(String message){ this.message = message; messageChange(); } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { int i = observers.indexOf(observer); if(i>0){ observers.remove(observer); } } @Override public void notifyObservers() { for(Object observer:observers){ Observer o = (Observer)observer; o.update(message); } } }
发送信息的类实现观察者(Observer)接口
package pattern.observer; public class SendEmail implements Observer{ private Subject subject; public SendEmail(Subject subject){ this.subject = subject; subject.registerObserver(this); } public void show(String message){ System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱"); } @Override public void update(String message) { show(message); } } public class SendPhone implements Observer{ private Subject subject; public SendPhone(Subject subject){ this.subject = subject; subject.registerObserver(this); } public void show(String message){ System.out.println("您在XXX订阅的信息有更新,更新内容:"+message + "。该信息来自XXXX"); } @Override public void update(String message) { show(message); } } public class SendWeb implements Observer{ private Subject subject; public SendWeb(Subject subject){ this.subject = subject; subject.registerObserver(this); } public void show(String message){ System.out.println("您订阅的信息有更新,更新内容:"+message); } @Override public void update(String message) { show(message); } }
最后实现控制器进行测试
package pattern.observer; public class MessageController { public static void main(String[] args) { String messageStr = "重大变化"; Message message = new Message(); SendPhone sendPhone = new SendPhone(message); SendWeb sendWeb = new SendWeb(message); SendEmail sendEmail = new SendEmail(message); message.setMessage(messageStr); } }
至此观察者模式完毕。
其实还有个疑问,为什么要在观察者本身里面注册呢?
public class SendEmail implements Observer{ private Subject subject; public SendEmail(Subject subject){ this.subject = subject; //为什么要在观察者保存Subject并且在初始化的时候用来注册 subject.registerObserver(this); } public void show(String message){ System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱"); } @Override public void update(String message) { show(message); } }
是不是希望可以在观察者本身取消对消息的订阅?
public class SendEmail implements Observer{ private Subject subject; public SendEmail(Subject subject){ this.subject = subject; this.subject.registerObserver(this); } public void show(String message){ System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱"); } @Override public void update(String message) { show(message); } //取消订阅 public void unsubscribe(){ subject.removeObserver(this); } }