观察者模式-------行为型设计模式
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,
它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
使用场景:通常意义上如果一个对象状态的改变需要通知很多对这个对象关注的一系列对象,就可以使用观察者模式。
概念很清晰,我们举个例子来理解一下观察者模式的含义,我们都在新浪微博中关注过某一位明星(假设,当然很多人已经不玩微博了),
每当这位明星发布一条动态时候,他的粉丝就都会知道。我们使用一张图来表示一下他们的关系。
上面这位明星在新浪微博上发了一条动态,说他会唱、跳rap等等。然后他的粉丝就都知道了。
从这个例子中我们可以看到,这里包含了两种人,第一种是明星,第二个是粉丝。转化为设计模式中的语言就是主题和观察者。
我们的明星的微博就相当于与一个主题,粉丝就是观察者,随时观察明星的动态。不过明星有权利让你关注,也有权利把你拉黑。现在我们从类图的角度来看一下:
从上面我们可以看到,这里面包含了两大类(主题和观察者)一共四个角色:
(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 dealFan(Fan fan); // 告诉粉丝我的动态 public void notify(String message); }
import java.util.ArrayList; import java.util.List; /** * 具体主题(ConcreteSubject):具体的明星 * * **/ public class ConcreteIdol implements Idol { private List<Fan> fanList = new ArrayList<>(); @Override public void addFan(Fan fan) { fanList.add(fan); } @Override public void dealFan(Fan fan) { fanList.remove(fan); } // 通知每个粉丝 @Override public void notify(String message) { for (Fan fan:fanList) { fan.update(message); } } }
public class Client { public static void main(String[] args) { // 明星 Idol idol = new ConcreteIdol(); //粉丝 Fan fanA = new ConcreteFan("吕布"); Fan fanB = new ConcreteFan("赵云"); Fan fanC = new ConcreteFan("后裔"); idol.addFan(fanA); idol.addFan(fanB); idol.addFan(fanC); // 明星发动态。粉丝获取通知 idol.notify("我,天神下凡一锤四"); } }
观察者模式的主要优点在于可以实现表示层和数据逻辑层的分离,并在观察目标和观察者之间建立一个抽象的耦合,支持广播通信;其主要缺点在于如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间,而且如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
其实还有一点需要我们去了解,在上面的例子当中我们的会发现,其实粉丝的消息是明星推过来的,还有一种观察者模式,也就是我们的粉丝主动去获取消息。
(1)推模型: 主题对象向观察者推送主题的详细信息,不管是否需要。
(2)拉模型:主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取。