设计模式之观察者模式
我们在电视上都看过这样一个场景,一个小孩拿着报纸在街上吆喝着,“卖报了,卖报了,xx鬼子侵占了中国东三省,张学良拱手让人”。然后想细看内容的人就会买一份报纸。又或者我们肯定都存在着这样一个群,这个微信群专门用于通知消息的,只要群里一有消息,我们就会知道。不管是我们订阅报纸的过程,还是接受群通知的过程,这其实就是观察者模式的灵活体现。这篇文章一起来分析了解一下观察者模式。
一、认识观察者模式
首先我们给出观察者模式的定义:
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
概念很清晰,我们举个例子来理解一下观察者模式的含义,我们都在新浪微博中关注过某一位明星(假设,当然很多人已经不玩微博了),每当这位明星发布一条动态时候,他的粉丝就都会知道。我们使用一张图来表示一下他们的关系。
1-观察者模式举例子.png上面这位明星在新浪微博上发了一条动态,说他会唱、跳rap等等。然后他的粉丝就都知道了。从这个例子中我们可以看到,这里包含了两种人,第一种是明星,第二个是粉丝。转化为设计模式中的语言就是主题和观察者。
我们的明星的微博就相当于与一个主题,粉丝就是观察者,随时观察明星的动态。不过明星有权利让你关注,也有权利把你拉黑。现在我们从类图的角度来看一下:
2-类图.png从上面我们可以看到,这里面包含了两大类(主题和观察者)一共四个角色:
(1)Subject:抽象主题,他把所有观察者对象保存在一个集合里,可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。意思就是明星把所有的粉丝都保存在一个账号里面,粉丝数量不限,可以新增粉丝也可以拉黑粉丝。
(2)ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。意思是我们的明星一有动态,就会把消息给粉丝。
(3)Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。这就是我们所有粉丝的抽象。
(4)ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。具体每一个粉丝。
观察者模式还是比较简单的,就是一个粉丝关注明星的实例。现在代码来实现一下。
二、代码实现观察者模式
这个例子我们还是那上面的例子来解释说明。
第一步:定义抽象观察者(Observer):抽象的粉丝
public interface Fan {
public void update(String message) ;
}
第二步:具体的观察者(concreteObserver):具体的粉丝
public class ConcreteFan implements Fan {
private String fanName;
public ConcreteFan(String fanName) {
this.fanName=fanName;
}
@Override
public void update(String message) {
System.out.println(fanName + "知道了:" + message+" 这条消息");
}
}
第三步:定义抽象主题(Subject):抽象明星
//明星接口:所有的明星都有这样的功能
public interface Idol {
//增加粉丝
public void addFan(Fan fan);
//拉黑粉丝
public void deFan(Fan fan);
//告诉粉丝我的动态
public void notify(String message);
}
第四步:具体主题(ConcreteSubject):具体的明星
public class ConcreteIdol implements Idol{
//保存所有的粉丝
private List<Fan> fanList = new ArrayList<Fan>();
@Override
public void addFan(Fan fan) {
fanList.add(fan);//增加粉丝
}
@Override
public void deFan(Fan fan) {
fanList.remove(fan);//拉黑粉丝
}
@Override
public void notify(String message) {
for (Fan fan : fanList) {
fan.update(message);//通知每一个粉丝消息
}
}
}
第五步:测试
public class Test {
public static void main(String[] args) {
//第一步:有一个明星
ConcreteIdol idol=new ConcreteIdol();
//第二步:有很多粉丝,这里给出来三个吧
ConcreteFan fanA=new ConcreteFan("张三");
ConcreteFan fanB=new ConcreteFan("李四");
ConcreteFan fanC=new ConcreteFan("王五");
//第三步:让粉丝去关注明星(反过来,明星把他们拉进来)
idol.addFan(fanA);
idol.addFan(fanB);
idol.addFan(fanC);
//第四步:明星发动态,粉丝获取动态
idol.notify("我会唱、跳、rap、篮球,music");
}
}
//张三知道了:我会唱、跳、rap、篮球,music 这条消息
//李四知道了:我会唱、跳、rap、篮球,music 这条消息
//王五知道了:我会唱、跳、rap、篮球,music 这条消息
代码就这么多,说起来这个观察者模式还是很简单的。下面我们就来分析一下这个观察者模式
三、分析观察者模式
观察者模式的主要优点在于可以实现表示层和数据逻辑层的分离,并在观察目标和观察者之间建立一个抽象的耦合,支持广播通信;其主要缺点在于如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间,而且如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
其实还有一点需要我们去了解,在上面的例子当中我们的会发现,其实粉丝的消息是明星推过来的,还有一种观察者模式,也就是我们的粉丝主动去获取消息。
(1)推模型: 主题对象向观察者推送主题的详细信息,不管是否需要。
(2)拉模型:主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取。
OK。观察者模式就先到这,如有问题还请批评指正:
欢迎关注微信公众号:java的架构师技术栈。回复指定关键字可获取编程技术各种视频资源等,包含java基础、进阶、框架、架构师系列。python、Android、微信小程序、神经网络、机器学习等等各种资源
微信公众号.png