介绍(以下部分内容来自维基百科) 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
这话听着很拗口,其实就是多个对象依赖于一个对象,并按照他的状态变化改变自身.
结构
主要有四个类:
抽象目标类(接口).
具体的目标类.
抽象的观察者类.
具体的观察者类.
具体场景及代码演示 你现在是一枚老韭菜!还是会写代码的韭菜!(简单易割还长得快).
你每天都炒股,只盯着两只股票,一个是阿里巴巴
,一个是腾讯
.你想在任何你能接触到的终端上面随时的看到最新的股市消息.
因此你开发了下面的代码(伪代码):
1 2 3 4 if 阿里巴巴 有变化 send (newest info) to 手机 send (newest info) to 电脑 send (newest info) to 手表
这样子没啥问题,但是以后想要修改的时候,比如你明天新买了个pad(韭菜哪有钱…),那你就需要修改上述的代码.
这样不是很符合开闭原则,因此使用观察者模式
将他重构一下.
由于jdk在util包里有对抽象目标
和抽象观察者
的定义,这里不做重复的定义,学习一下这两个接口.
抽象目标(被观察者) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package java.util;public class Observable { private boolean changed = false ; private Vector<Observer> obs; public Observable () { obs = new Vector <>(); } public synchronized void addObserver (Observer o) { if (o == null ) throw new NullPointerException (); if (!obs.contains(o)) { obs.addElement(o); } } public synchronized void deleteObserver (Observer o) { obs.removeElement(o); } public void notifyObservers () { notifyObservers(null ); } 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); } public synchronized int countObservers () { return obs.size(); } }
可以看出,他定义并实现了结构图中的三个方法,添加观察者
,删除观察者
,通知观察者
.存储观察者使用的Vector.保证对观察者的添加及删除操作线程安全.对Vector想了解的朋友可以移步Vector源码阅读 .
抽象观察者 1 2 3 4 public interface Observer { void update (Observable o, Object arg) ; }
Observer
只定义了一个方法,就是更新自身.
好,那么到了重头戏了,我们通过自己的实现来重构上面的项目.
股票类(具体的某个被观察者) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.huyan.demo.observer;import java.util.Observable;import java.util.Observer;public class Stock extends Observable { private String name; public Stock (String name) { this .name = name; } @Override public synchronized void addObserver (Observer o) { super .addObserver(o); } @Override public synchronized void deleteObserver (Observer o) { super .deleteObserver(o); } @Override public void notifyObservers (Object arg) { super .notifyObservers(arg); } public void stockUp () { System.out.println("涨了涨了!牛逼!" ); super .setChanged(); } @Override public String toString () { return "这里是股票:" + name; } }
我们定义并实现了Stock类,拥有属性:名字.
以及几个重写的方法,其实完全调用了父类的方法,这里只是写出来方便看.
此外定义了一个股票上涨
的方法,在这个方法里面调用了父类的serChange
方法,代表着此时,被观察者发生了变化.
具体观察者(PC和手机) 1 2 3 4 5 6 7 8 public class PC implements Observer { @Override public void update (Observable o, Object arg) { System.out.println("------------PC已经更新." ); System.out.println(arg.toString()); } }
1 2 3 4 5 6 7 8 public class Phone implements Observer { @Override public void update (Observable o, Object arg) { System.out.println("------------Phone已经更新." ); System.out.println(arg.toString()); } }
这里定义了PC和手机,实现了唯一的update
方法,在里面更新自己信息并打印,标识自己被通知到了
.
测试 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void test () { Stock stock = new Stock ("阿里巴巴" ); stock.addObserver(new PC ()); stock.addObserver(new Phone ()); stock.stockUp(); stock.notifyObservers("阿里巴巴大涨0.01%" ); }
这里我们定义了一个股票(被观察者),然后给它添加了手机和PC(观察者),之后股票上涨(被观察者变化),看一下结果,观察者是否收到消息并更新自身信息.
输出结果 1 2 3 4 5 涨了涨了!牛逼! ------------Phone已经更新. 阿里巴巴大涨0.01% ------------PC已经更新. 阿里巴巴大涨0.01%
可以看到,这里在被观察者发生变化后,所有(两个)的观察者都受到了消息并且做出了反应.
如何扩展呢? 这样重构完之后,扩展变得十分方便,比如我们新买了pad.只需要新建一个Pad
类,然后在添加观察者步骤,将其添加即可.
想换一只股票观察或者添加一直股票,只需要new一个股票的对象重复上述操作即可.
总结 在对象观察一对多
的情况下,观察者模式成功的将我们的系统解耦,并提高了系统的可扩展性,但是有没有问题呢?
有,如果这里的终端不只是个人的,而是一群人的,即:观察者过多,一个个通知将会很慢.
因此,在发现场景适合后,仍需做一些调研,才可以对代码进行重写,千万不要得不偿失.
完。
ChangeLog
2018-12-28 完成
以上皆为个人所思所得,如有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文链接。
联系邮箱:huyanshi2580@gmail.com
更多学习笔记见个人博客——>呼延十