这里引用官方的一段话简单介绍下设计模式:
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
这里讲观察者模式将从以下几个方面进行介绍:
1、观察者模式定义
2、观察者模式的UML
3、使用场景
4、代码实现
5、扩展
从官方的定义来讲:
简单来说:
2、UML图
3、使用场景
一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
一个对象必须通知其他对象,而并不知道这些对象是谁。
需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
4、代码实现:
A、抽象主题
package com.tcyl.wyf.observe.subject; import com.tcyl.wyf.observe.IObserver; /*** * 抽象被观察者接口 -- 主题接口 * 声明了添加、删除、通知观察者方法 * @author yfwu * */ public interface ISubject { void registerObserver(IObserver o); void removeObserver(IObserver o); void notifyObserver(); }
2、具体主题
package com.tcyl.wyf.observe.subject.impl; import com.tcyl.wyf.observe.IObserver; import com.tcyl.wyf.observe.subject.ISubject; import java.util.ArrayList; import java.util.List; /** * Created by aaronng.wu on 2018/7/2. */ public class ConcreteSubject implements ISubject { //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程 private List<IObserver> list; private String message; //初始化具体主题容纳观察者数量 public ConcreteSubject(){ list = new ArrayList<>(16); } @Override public synchronized void registerObserver(IObserver o) { if(null == o){ throw new NullPointerException(); } list.add(o); } @Override public synchronized void removeObserver(IObserver o) { if(list.contains(o)){ list.remove(o); } } @Override public void notifyObserver() { for(IObserver o : list){ o.update(message); } } public void sendInfomation(String s) { this.message = s; System.out.println("发布推送消息: " + s); //消息更新,通知所有观察者 notifyObserver(); } }
C、抽象观察者
package com.tcyl.wyf.observe; /*** * 抽象观察者 * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。 * @author yfwu * */ public interface IObserver{ void update(String message); }
D、具体观察者
package com.tcyl.wyf.observe.impl; import com.tcyl.wyf.observe.IObserver; /** * 具体观察者 * 实现了update方法 * @author yfwu * */ public class ConcreteObserver implements IObserver { private String name; private String message; public ConcreteObserver(String name){ this.name = name; } @Override public void update(String message) { this.message = message; read(); } public void read() { System.out.println(name + " 收到推送消息: " + message); } }
运行结果:
代码注释也比较详细,如有问题,请留言。
5、扩展
在观察者模式中,又分为推模型和拉模型两种方式。
● 推模型
主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
● 拉模型
主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。
根据上面的描述,发现前面的例子就是典型的推模型,下面给出一个拉模型的实例。
两种模式的比较
■推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值。
■推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是主题对象本身,这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。