主页传送门:💁 传送
1.观察者模式定义
观察者模式(Observer Pattern)是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。其定义如下:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
即:定义对象之间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
其通用类图如下:
2.观察者模式的角色
观察者模式所涉及的角色有:
-
抽象主题(Subject)角色:
抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。 -
具体主题(ConcreteSubject)角色:
将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。 -
抽象观察者(Observer)角色:
为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。 -
具体观察者(ConcreteObserver)角色:
存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。
3.观察者模式实战案例
3.1.场景说明
下面举一个具体实例,假设上班时间有一部分同事在看股票,一部分同事在看NBA,这时老板回来了,前台通知了部分同事老板回来了,这些同事及时关闭了网页没被发现,而没被通知到的同事被抓了个现行,被老板亲自“通知”关闭网页
3.2.关系类图
使用观察者模式来实现的结构图如下:
3.3.代码实现
- 通知者接口
public interface Subject {
//增加
public void attach(Observer observer);
//删除
public void detach(Observer observer);
//通知
public void notifyObservers();
//状态
public void setAction(String action);
public String getAction();
}
- 观察者
public abstract class Observer {
protected String name;
protected Subject subject;
public Observer(String name, Subject subject) {
this.name = name;
this.subject = subject;
}
public abstract void update();
}
- 具体通知者
前台Secretary和老板Boss作为具体通知者,实现Subject接口。这里只给出Secretary类的代码,Boss类与之类似。
public class Secretary implements Subject {
//同事列表
private List<Observer> observers = new LinkedList<>();
private String action;
//添加
@Override
public void attach(Observer observer) {
observers.add(observer);
}
//删除
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
//通知
@Override
public void notifyObservers() {
for(Observer observer : observers) {
observer.update();
}
}
//前台状态
@Override
public String getAction() {
return action;
}
@Override
public void setAction(String action) {
this.action = action;
}
}
- 具体观察者
StockObserver是看股票的同事,NBAObserver是看NBA的同事,作为具体观察者,继承Observer类。这里只给出StockObserver类的代码,NBAObserver类与之类似。
public class StockObserver extends Observer {
public StockObserver(String name, Subject subject) {
super(name, subject);
}
@Override
public void update() {
System.out.println(subject.getAction() + "\n" + name + "关闭股票行情,继续工作");
}
}
- 前台作为通知者进行通知(Client)
前台作为通知者,通知观察者。这里添加adam和tom到通知列表,并从通知列表中删除了adam,测试没在通知列表中的对象不会收到通知。
public class Client {
public static void main(String[] args) {
//前台为通知者
Secretary secretary = new Secretary();
StockObserver observer = new StockObserver("adam", secretary);
NBAObserver observer2 = new NBAObserver("tom", secretary);
//前台通知
secretary.attach(observer);
secretary.attach(observer2);
//adam没被前台通知到,所以被老板抓了个现行
secretary.detach(observer);
//老板回来了
secretary.setAction("小心!Boss回来了!");
//发通知
secretary.notifyObservers();
}
- 老板作为通知者进行通知(Client)
老板作为通知者,通知观察者。这里将tom从老板的通知列表中移除,老板只通知到了adam
public class Client {
public static void main(String[] args) {
//老板为通知者
Boss boss = new Boss();
StockObserver observer = new StockObserver("adam", boss);
NBAObserver observer2 = new NBAObserver("tom", boss);
//老板通知
boss.attach(observer);
boss.attach(observer2);
//tom没被老板通知到,所以不用挨骂
boss.detach(observer2);
//老板回来了
boss.setAction("咳咳,我大Boss回来了!");
//发通知
boss.notifyObservers();
}
}
4.观察者模式优缺点
观察者模式的优点包括:
- 解耦:观察者模式有效地解耦了主题和观察者之间的依赖关系,主题不再需要直接管理观察者,而观察者也不再需要了解主题的具体实现。
- 抽象:观察者模式让耦合的双方都依赖于抽象,提高了系统的可扩展性和可维护性。
- 通知:观察者模式可以支持多种通知方式,包括异步通知,这样可以提高系统的效率和性能。
然而,观察者模式也存在一些缺点:
- 开发复杂:观察者模式需要实现三个接口(主题,观察者和通知),并编写相应的代码,这增加了开发和维护的复杂性。
- 顺序执行:观察者模式的通知是顺序执行的,如果有一个观察者的操作失败了,可能会影响到其他观察者的执行。
- 状态共享:观察者模式需要共享主题的状态,如果主题的状态是复杂的,或者多个观察者的状态之间存在依赖关系,那么这可能会导致开发和维护变得更加复杂。
5.观察者模式适用场景
观察者模式适用于以下场景:
- 发布-订阅系统:这是观察者模式最经典的用途。在这种场景中,发布者发布消息并通知所有已订阅该消息的订阅者。观察者模式可以用来实现这种通知机制。
- GUI开发:在图形用户界面开发中,当用户与界面交互时,观察者模式可以用来通知其他组件。例如,当用户点击按钮时,可以自动更新相关的其他组件。
- MVC模式:在MVC模式中,当模型发生变化时,视图会自动更新。这种机制可以通过观察者模式来实现。具体来说,当模型对象状态改变时,所有依赖于它的视图都会接收到通知并自动更新。
除了以上场景,观察者模式还适用于任何需要实现一对多依赖关系的场景。
6.观察者模式总结
观察者模式是一种设计模式,用于在对象之间建立一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式在许多领域都有广泛的应用,如GUI开发、事件处理、状态管理等。
总的来说,观察者模式在某些情况下可以非常有用,但是也需要根据实际需求来考虑其适用性。在实际开发中,我们可以使用观察者模式来实现新闻推送、消息广播等需求,以提高代码的可维护性和可扩展性。
如果喜欢的话,欢迎 🤞关注 👍点赞 💬评论 🤝收藏 🙌一起讨论
你的支持就是我✍️创作的动力! 💞💞💞