前言
先简要说说观察者模式的定义与组成吧。
观察者模式定于与组成
通俗来讲,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象在状态上发生变化时,通知所有观察者对象,让它们可以主动的更新自己。观察者模式主要分为四部分:抽象主题角色;抽象观察者角色;具体主题角色;具体观察者角色。
接下来看看我自定义的观察者模式吧。
自定义观察者模式
- 先说说需求吧:
通过观察者模式来实现一个简单的消息订阅。
- 接下来说说具体的设计抽象:
想想观察者的主要部分,大致可以抽象出这样几个类:Subject(主题),Observer(观察者),ConcreateSubject(具体的主题角色),ConcreteObserver(具体的观察者角色)
抽象出这几个类后,可以画出如下的类图:
- 具体的代码实现:
抽象角色:Subject:AbstractSubject:public interface Subject { /** * 消息订阅 * @param observer */ public void subscribe(Observer observer); /** * 广播消息 */ public void publish(); /** * 退订某个服务 * @param observer */ public void unSubscribe(Observer observer); /** * 退订全部服务 */ public void unSubscribeAllServers(); }
Observer:public abstract class AbstractSubject implements Subject { //观察者List private List<Observer> observers; public AbstractSubject() { this.observers = Lists.newArrayList(); } public void subscribe(Observer observer) { if (null == observer) { return; } observers.add(observer); } public void publish() { for (Observer observer : observers) { observer.update(this); } } public void unSubscribe(Observer observer) { System.out.println("unsubscribe...\n"); observers.remove(observer); } public void unSubscribeAllServers() { observers.clear(); } }
具体角色:public interface Observer { public void update(Subject subject); }
ConcreateSubject:
ConcreateObserver:public class ConcreateSubject extends AbstractSubject { //消息状态 private int status; //消息主题 private String subject; public ConcreateSubject(String subject) { super(); status = Status.NOT_SEND.getStatus(); this.subject = subject; } //消息状态变更 public void changed(int newStatus) { this.status = newStatus; publish(); } public String getSubject() { return subject; } public int getStatus() { return status; } }
public class ConcreateObserver implements Observer { //观察者名字 private String name; //订阅主题 private Subject subject; public ConcreateObserver(String name, Subject subject) { this.name = name; this.subject = subject; subject.subscribe(this); } //一般仅仅只是通知的时候可以换个名字,但是有业务操作的时候就建议用update public void update(Subject subject) { ConcreateSubject concreateSubject = (ConcreateSubject) subject; System.out.println("observerName = " + this.name + "\n" + concreateSubject.getSubject() + " changed...." + "\n" + "status = " + Status.getStatus(concreateSubject.getStatus()).getStatusName() + "\n"); } @Override public String toString() { return "ConcreateObserver{" + "name='" + name + '\'' + ", subject=" + subject + '}'; } }
最后看看具体的调用:
Client:
public class Client { public static void main(String args[]) { //定义一个主题 ConcreateSubject subject = new ConcreateSubject("com.sankuai.sendMessage"); //定义两个观察者 ConcreateObserver sendObserver = new ConcreateObserver("send_message", subject); ConcreateObserver reSendMessage = new ConcreateObserver("re_send_message", subject); //更改消息状态 subject.changed(Status.SEND.status); } }
后记
在设计观察者模式的时候一定要注意以下几点:
- 首先要明确谁是观察者谁是被观察者,只要明确谁是关注对象,问题也就明白了,一般观察者与被观察者之间是一对多的关系,一个被观察者可以有多个观察者,举个例子吧,比如一个编辑框,有鼠标点击的观察者,还有内容改变的观察者,等等。
- 被观察者在发送广播通知的时候,无需指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知;
- 被观察者至少需要有三个方法:添加监听者,移除监听者,通知观察者;观察者至少有一个方法:更新,更新当前的内容,并作出处理;
- 最后说说该模式应用场景:a.对一个对象的状态的更新需要其他对象同步更新,或者一个对象的更新需要依赖于另外的对象更新;b.对象仅需要将自己的更新通知给其他的对象,不需要知道其他对象的细节,比如消息推送。
推模型和拉模型:
观察者模式根据其侧重的功能还可以分为推模型和拉模型
推模型:被观察者像向观察者推送主题相关信息,不管观察者是否需要,一般这种模型的实现中,会把呗观察者对象中的信息通过update(Object obj)传递给观察者;
拉模型:被观察者在通知观察者的时候,只需要传递少量信息。如果观察者需要更具体的信息,有观察者主动到被观察者对象中获取,相当于是观察者到被观察者对象中拉取数据。一般这种模型的视线中,会把被观察者对象自身通过update方法传递给观察者update(Subject subject),这样在观察者需要获取数据的时候,就可以通过这个引用来获取。