一、描述
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。也称为发布-订阅模式。
角色:
1.抽象目标类:除自身业务逻辑外,包含增加、删除、唤醒观察者功能。
2.具体目标类:为那些在目标发生改变时需获取通知的对象定义一个更新接口。
2.抽象观察类:定义响应抽象方法。
3.具体观察类:继承抽象观察类,实现抽象方法。
类图:
二、优点
1.目标和观察者之间的耦合是最小的。一个目标所知道的仅仅是它有一系列的观察者,但是不知道这些观察者是哪些类,目标类只需要负责通知就可以了。
2.支持广播通信。通知被自动广播给所有已向该目标对象登记的有关对象。
三、缺点
1.意外的更新。因为一个观察者并不知道其他观察者的存在,它可能对改变目标的最终代价一无所知。
2.如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会话费很多的时间。
3.如果观察者和观察目标之间有循环依赖的话,观察目标会触发他们之间进行循环调用,可能导致系统崩溃。
四、适用场景
1.当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
2.当一个对象必须通知其他对象,而它又不能假定其他对象是谁。
五、示例
以“交通灯亮,其他对象针对交通灯不同的颜色作出不同反应为例”。
1.抽象观察者类
- public abstract class AbstractObserver {
- /**
- * 作出反应
- *
- * @param type
- */
- abstract void update(Integer type);
- }
2.具体观察者类,汽车、行人、自行车等
(1)汽车
- public class CarObserver extends AbstractObserver {
- @Override
- void update(Integer type) {
- System.out.print("我是轿车:");
- if (Objects.equal(type, 1)) {
- System.out.println("踩刹车,停车");
- } else if (Objects.equal(type, 2)) {
- System.out.println("开始行驶");
- } else if (Objects.equal(type, 3)) {
- System.out.println("缓慢行驶");
- }
- }
- }
(2)行人
- public class PedestriansObserver extends AbstractObserver {
- @Override
- void update(Integer type) {
- System.out.print("我是行人:");
- if (Objects.equal(type, 1)) {
- System.out.println("原地站立");
- } else if (Objects.equal(type, 2)) {
- System.out.println("行走");
- } else if (Objects.equal(type, 3)) {
- System.out.println("行走,注意车辆");
- }
- }
- }
(3)自行车
- public class BikeObserver extends AbstractObserver {
- @Override
- void update(Integer type) {
- System.out.print("我是自行车:");
- if (Objects.equal(type, 1)) {
- System.out.println("捏闸,停车");
- } else if (Objects.equal(type, 2)) {
- System.out.println("开始骑行");
- } else if (Objects.equal(type, 3)) {
- System.out.println("骑行,注意车辆");
- }
- }
- }
3.抽象目标类
- public abstract class AbstractSubject {
- public List<AbstractObserver> observerList = new ArrayList<>();
-
- public void addObservers(AbstractObserver observer) {
- observerList.add(observer);
- }
-
- public void removeObserver(AbstractObserver observer) {
- observerList.remove(observer);
- }
-
- /**
- * 当前目标的行为
- *
- * @param type
- */
- public abstract void doAction(Integer type);
- }
4.具体目标类,交通灯类
- public class TrafficFlightSubject extends AbstractSubject {
- @Override
- public void doAction(Integer type) {
- if (Objects.equal(type, 1)) {
- System.out.println("红灯亮");
- } else if (Objects.equal(type, 2)) {
- System.out.println("绿灯亮");
- } else if (Objects.equal(type, 3)) {
- System.out.println("黄灯亮");
- }
- for (AbstractObserver observer : observerList) {
- observer.update(type);
- }
- }
- }
5.测试类
- public class Client {
- public static void main(String[] args) {
- TrafficFlightSubject subject = new TrafficFlightSubject();
-
- CarObserver carObserver = new CarObserver();
- subject.addObservers(carObserver);
-
- PedestriansObserver pedestriansObserver = new PedestriansObserver();
- subject.addObservers(pedestriansObserver);
-
- BikeObserver bikeObserver = new BikeObserver();
- subject.addObservers(bikeObserver);
-
- //红灯
- subject.doAction(1);
- System.out.println();
-
- //绿灯
- subject.doAction(2);
- System.out.println();
-
- //黄灯
- subject.doAction(3);
- }
- }
测试效果:
六、注意事项
观察者和中介者模式有些类似,但是不要弄混。二者的区别如下:
1.行为不同,观察者模式的目标类自身会有操作,之后通知观察者列表。中介者模式是直接通知对应的对象。
2.目的不同,观察者模式主要是一堆观察者观察目标类,当目标类有所操作之后,同时作出反应。中介者模式是一个对象通过中介通知另外一个对象。
3.目标群体不同,观察者模式中,目标类并不清楚观察者列表具体包含哪些对象;中介者模式的通知模式是清楚要通知哪些对象的。
推荐一篇解释二者对比比较透彻的文章:https://www.cdsy.xyz/computer/programme/design_pattern/230201/cd40017.html