Loading... # 设计模式(十一)——观察者模式 ## 参考 > 大话设计模式  ——  程杰 著 ## 目录 [设计模式(一)——简单工厂模式](https://www.princelei.club/archives/67.html) [设计模式(二)——策略模式](https://www.princelei.club/archives/68.html) [设计模式(三)——设计原则](https://www.princelei.club/archives/116.html) [设计模式(四)——装饰模式](https://www.princelei.club/archives/117.html) [设计模式(五)——代理模式](https://www.princelei.club/archives/119.html) [设计模式(六)——工厂方法模式](https://www.princelei.club/archives/132.html) [设计模式(七)——原型模式](https://www.princelei.club/archives/133.html) [设计模式(八)——模板方法模式](https://www.princelei.club/archives/134.html) [设计模式(九)——外观模式](https://www.princelei.club/archives/135.html) [设计模式(十)——建造者模式](https://www.princelei.club/archives/136.html) [设计模式(十一)——观察者模式](https://www.princelei.club/archives/137.html) [设计模式(十二)——抽象工厂模式](https://www.princelei.club/archives/138.html) [设计模式(十三)——状态模式](https://www.princelei.club/archives/139.html) [设计模式(十四)——适配器模式](https://www.princelei.club/archives/140.html) [设计模式(十五)——备忘录模式](https://www.princelei.club/archives/141.html) [设计模式(十六)——组合模式](https://www.princelei.club/archives/147.html) [设计模式(十七)——迭代器模式](https://www.princelei.club/archives/148.html) [设计模式(十八)——单例模式](https://www.princelei.club/archives/157.html) [设计模式(十九)——桥接模式](https://www.princelei.club/archives/159.html) [设计模式(二十)——命令模式](https://www.princelei.club/archives/160.html) [设计模式(二十一)——职责链模式](https://www.princelei.club/archives/161.html) [设计模式(二十二)——中介者模式](https://www.princelei.club/archives/162.html) [设计模式(二十三)——享元模式](https://www.princelei.club/archives/163.html) [设计模式(二十四)——解释器模式](https://www.princelei.club/archives/173.html) [设计模式(二十五)——访问者模式](https://www.princelei.club/archives/174.html) ## 何为观察者模式 - 观察者模式又叫发布-订阅(Publish/Subscribe)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。 ## 示例 Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。 ``` /** * 抽象通知者 */ public interface Subject { //增加观察者 public void attach(Observer observer); //移除观察者 public void detach(Observer observer); //通知 public void notifie(); } ``` Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update()方法,这个方法叫做更新方法。 ``` /** * 抽象观察者 */ public interface Observer { void update(); } ``` ConcreteSubject类,叫做具体主题或者具体通知者,将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。 ``` /** * 具体通知者 */ public class ConcreteSubject implements Subject { //具体被观察者状态 private String subjectState; private List<Observer> observers = new ArrayList<>(); @Override public void attach(Observer observer) { observers.add(observer); } @Override public void detach(Observer observer) { observers.remove(observer); } @Override public void notifie() { observers.forEach(Observer::update); } public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; } } ``` ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。 ``` /** * 具体观察者 */ public class ConcreteObserver implements Observer { private String name; private String observerState; private ConcreteSubject subject; public ConcreteObserver(ConcreteSubject subject, String name) { this.subject = subject; this.name = name; } @Override public void update() { observerState = subject.getSubjectState(); System.out.println("观察者" + name + "的新状态是" + observerState); } public ConcreteSubject getSubject() { return subject; } public void setSubject(ConcreteSubject subject) { this.subject = subject; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ConcreteObserver that = (ConcreteObserver) o; return name.equals(that.name); } @Override public int hashCode() { return name.hashCode(); } } ``` 客户端代码 ``` /** * 客户端 */ public class MainClass { public static void main(String[] args) { ConcreteSubject s = new ConcreteSubject(); s.attach(new ConcreteObserver(s, "X")); s.attach(new ConcreteObserver(s, "Y")); s.attach(new ConcreteObserver(s, "Z")); s.setSubjectState("ABC"); s.notifie(); } } ``` 输出: ``` 观察者X的新状态是ABC 观察者Y的新状态是ABC 观察者Z的新状态是ABC ``` ## 观察者模式的特点 将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。当一个对象的改变需要同时改变其它对象而且它却不知道具体有多少对象有待改变时,应该考虑使用观察者模式。一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。 ## 观察者模式的不足 - ‘抽象通知者’还是依赖‘抽象观察者’,万一没有抽象观察者这样的接口,通知功能就完成不了,如:要通知第三方封装好的类的实例。 - 每个具体的观察者也不一定就是update()方法要被调用。 ### 解决方法 事件委托 ## 事件委托实现 ``` /** * 事件对象封装类 */ public class Event { //要执行方法的对象 private Object object; //要执行的方法名称 private String methodName; //要执行方法的参数 private Object[] params; //要执行方法的参数类型 private Class[] paramTypes; public Event() { } public Event(Object object, String methodName, Object... args) { this.object = object; this.methodName = methodName; this.params = args; contractParamTypes(this.params); } //根据参数数组生成参数类型数组 private void contractParamTypes(Object[] params) { this.paramTypes = new Class[params.length]; for (int i = 0; i < params.length; i++) { this.paramTypes[i] = params[i].getClass(); } } public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public Object[] getParams() { return params; } public void setParams(Object[] params) { this.params = params; } public Class[] getParamTypes() { return paramTypes; } public void setParamTypes(Class[] paramTypes) { this.paramTypes = paramTypes; } /** * 根据该对象的方法名,方法参数,利用反射机制,执行该方法 * * @throws Exception */ public void invoke() throws Exception { Method method = object.getClass().getMethod(this.getMethodName(), this.getParamTypes()); if (null == method) { return; } method.invoke(this.getObject(), this.getParams()); } } ``` ``` /** * 事件处理者 */ public class EventHandler { private List<Event> events; public EventHandler(){ events=new ArrayList<>(); } //添加某个对象要执行的事件,及需要的参数 public void addEvent(Object object,String methodName,Object...args){ events.add(new Event(object,methodName,args)); } //通知所有的对象执行指定的事件 public void notifyX() throws Exception{ for(Event e : events){ e.invoke(); } } } ``` ``` /** * 抽象通知者 */ public abstract class Subject { private EventHandler eventHandler = new EventHandler(); public EventHandler getEventHandler() { return eventHandler; } public void setEventHandler(EventHandler eventHandler) { this.eventHandler = eventHandler; } /** *增加观察者 */ public abstract void attach(Object object, String methodName, Object... args); /** * 通知 */ public abstract void notifie(); } ``` ``` /** * 具体通知者 */ public class ConcreteSubject extends Subject { @Override public void attach(Object object, String methodName, Object... args) { this.getEventHandler().addEvent(object, methodName, args); } @Override public void notifie() { try { this.getEventHandler().notifyX(); } catch (Exception e) { e.printStackTrace(); } } } ``` ``` /** * 具体观察者A */ public class ConcreteObsercerA { private String name; public ConcreteObsercerA(String name){ this.name = name; } public void abc(){ System.out.println("观察者"+name+"abc"); } } ``` ``` /** * 具体观察者B */ public class ConcreteObsercerB { private String name; private String obsercerState; public ConcreteObsercerB(String name) { this.name = name; } public void def(String state) { obsercerState = state; System.out.println("观察者" + name + "的状态是" + obsercerState); } } ``` ``` /** * 客户端 */ public class MainClass { public static void main(String[] args) { Subject subject = new ConcreteSubject(); subject.attach(new ConcreteObsercerA("X"), "abc"); subject.attach(new ConcreteObsercerB("Y"), "def","DEF"); subject.notifie(); } } ``` 输出: ``` 观察者Xabc 观察者Y的状态是DEF ``` Last modification:June 11th, 2020 at 06:24 pm © 允许规范转载