观察者模式的两种实现和比较
来源:互联网 发布:mac物理地址不匹配 编辑:程序博客网 时间:2024/06/03 19:04
为什么要用观察者模式?
GOF那本书里面是这样描述的:
将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一 致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性。
情景
假设我们有一组数据要用于不同的方案,比如schemeA和schemeB,出于某种原因,A和B之间不能通信,他们不知道彼此的存在。要求当方案改变时可以同时通知到A和B。
BadSolution :
一个比较不好的解决方法是在数据类里面保持SchemeA和SchemeB的对象来改变数据,Data的代码如下所示:
private SchemeA schemeA; private SchemeB schemeB; public void setData(int data1,int data2){ schemeA = new SchemeA(); schemeB = new SchemeB(); schemeA.setData(data1,data2); schemeB.setData(data1,data2); }
通过调用setData()来改变数据,这样的做法可以实现但确是一个不好的设计,比如当方案B要被方案C代替了,那么Data类的数据要重写。再者,如果有很多方案的话,这个setData()方法需要将这些方案都写进去。简单来说就是高度耦合,重用性低。这种方案的类顺序图如下所示:
观察者模式来实现
jdk里面实现了观察者模式,这里我们先自己实现这个模式,后文再讲jdk里面的实现。
首先我们定义一个主题Subject:
public interface Subject { void addObserver(Observer o); void removeObserver(Observer o); void notifyAllObservers();}
注意到他有三个方法分别可以注册观察者,移除观察者和通知所有观察者。Data类通过实现这个接口来为SchemeA和SchemeB传送消息。
Data类实现如下:
public class Data implements Subject { ArrayList observers; private int data1, data2; public Data(){ this.observers = new ArrayList(); } @Override public void addObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer o) { int i = observers.indexOf(o); if(i>0) observers.remove(i); } @Override public void notifyAllObservers() { for (Object obj:observers){ Observer observer = (Observer)obj; observer.update(data1,data2); } } public void setData(int data1,int data2){ this.data1 = data1; this.data2 = data2; measureChange(); } public void measureChange(){ notifyAllObservers(); }}
而观察者类则可以这样实现:
public interface Observer { void update(int data1,int data2);}
SchemeA和SchemeB通过实现这个接口的update方法来更新数据。那么Data类怎么知道SchemeA和SchemeB就是观察者呢?一个可行的实现是在构造SchemeA和SchemeB的时候传入Data对象,然后调用Data类的addObserver()方法来为两个方案类注册。
这个系统的类交互图如下所示:
这样设计有什么好处呢?
我们可以看Data类里面的代码,完全没有SchemeA和SchemeB的痕迹,也就是说,无论有多少个方案需要数据,无论方案怎么改变,这个Data类都不需要发生改变,也就可以重用了。而且方案A和方案B之间不知道彼此的存在就能实现数据的同时更新。
用jdk提供的功能来实现
我们的Data类变得简单起来了,因为java.util.Obserable这个类给我们做了很多事情。
public class Data extends Observable { private int data1,data2; public Data(){ } public void setData(int data1,int data2){ this.data1 = data1; this.data2= data2; mesureChange(); } public void mesureChange(){ setChanged(); notifyObservers(); } public int getData1() { return data1; } public int getData2() { return data2; }}
我们只需要像之前实现Subject类那样来继承Observable这个类(不过使用继承的方式会有很多限制,因为java不允许多重继承但可以实现多个接口)。注意measureChange()这个方法,里面调用Observable的两个方法setChange()和notifyObervers()方法。这两个方法的实现都很简单。
protected synchronized void setChanged() { changed = true; }
public void notifyObservers() { notifyObservers(null); }
调用有参的notifyObservers()方法。
public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); }
这样我们只要使SchemeA和SchemeB方法都实现java.util.Observer接口就可以了。
public class SchemeA implements Observer { private int data1,data2; private Observable o; public SchemeA(Observable o){ o.addObserver(this); } @Override public void update(Observable o, Object arg) { if(o instanceof Data){ data1 = ((Data) o).getData1(); data2 = ((Data) o).getData2(); } display(); } public void display(){ System.out.println("SchemeA display data1 is "+data1+" data2 is "+data2); }}
使用jdk内置的观察者模式代码简单多了,但是却有时候会有限制,比如Data类已经继承了Observable类,就不能继承其他类了。注意Observable是一个类而不是一个接口。
献上github代码:
https://github.com/cris1313/mingle/tree/master/src/demo/designpatern/observer
完。
- 观察者模式的两种实现和比较
- Perl 面向对象编程的两种实现和比较
- Perl面向对象编程的两种实现和比较
- Perl 面向对象编程的两种实现和比较:
- Python快速排序的两种实现和比较
- 三种观察者模式的C#实现
- 观察者模式和php实现
- 数据访问两种模式的比较
- 第九章 两种模式的比较
- C++ 两种设计模式:单例模式和观察者监听者模式
- 黑马程序员笔记:单例模式的简单实现与两种实现方法的比较(饿汉式和懒汉式)(一)
- 黑马程序员笔记:单例模式的简单实现与两种实现方法的比较(饿汉式和懒汉式)(二)
- 观察者模式的简单实现
- 观察者模式的java实现
- swift观察者模式的实现
- swift观察者模式的实现
- 简单实现的观察者模式
- 观察者模式的C#实现
- 单例模式
- 解决腾讯云服务器启动tomcat巨慢导致浏览器无法加载的方案
- File.io读取文件(四)
- js 微信端 信息一键导入 通讯录
- 【Java Utility】Jsoup网页爬虫工具--从URL加载Document【五】
- 观察者模式的两种实现和比较
- 分享下最近写的开源电子书《我的职业是前端工程师》
- mysql 关联条件 中使用 like
- 当前目录下maven生成jar并带lib文件夹啊
- HashMap之原理及死锁
- 未发布 手机可以同电脑端连接 测试 操作步奏
- Advanced Architecture Lab
- 后台和前台对json的处理
- Html+Css+Js_之table每隔3行显示不同的两种颜色