【设计模式】20.行为型模式-观察者(Observer)
一、描述
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。也称为发布-订阅模式。
角色:
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.cnblogs.com/yaopengfei/p/13502916.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现