您现在的位置是:首页 >技术交流 >【设计模式】观察者模式篇网站首页技术交流
【设计模式】观察者模式篇
Observer Pattern
1、定义
观察者模式是一种设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生改变时,它的所有依赖对象都会收到通知并自动更新。
在观察者模式中,有两个主要角色:被观察者和观察者。被观察者维护了一个观察者列表,并提供了添加和删除观察者的方法。当被观察者的状态发生改变时,它会遍历观察者列表并调用每个观察者的更新方法,通知它们状态的改变。
观察者模式可以被应用于许多场景中,例如用户界面组件、事件处理等。它使得对象之间的耦合度降低,因为被观察者不需要知道观察者的具体实现,而只需要通知它们即可。同时,观察者模式也提高了代码的可维护性和可扩展性,因为可以方便地添加或移除观察者,而不需要修改被观察者的代码。
2、优缺点
优点:
- 松耦合性:观察者模式实现了松耦合,使得观察者和主题之间的依赖关系变得比较小,各自可以独立地进行扩展。
- 可重用性:观察者模式使得主题和观察者之间的关系可以被复用,不需要修改原有代码即可增加新的观察者。
- 支持广播通信:观察者模式支持广播通信,当主题对象发生改变时,会向所有的观察者发送通知,保证所有观察者对象的状态都是最新的。
缺点:
- 观察者过多导致性能问题:如果观察者数量过多或者观察者的处理时间过长,会降低系统的性能。
- 顺序执行问题:观察者模式中,各个观察者是按照添加的顺序执行的,如果观察者之间有依赖关系,可能会导致程序出现问题。
- 异常处理问题:如果一个观察者出现了异常,可能会影响整个系统的稳定性。
3、比喻了解
观察者模式可以通过生活中的例子来理解。
假设你是一位球迷,你想要及时了解你最喜欢的足球队的比赛成绩。于是你订阅了这个足球队的官方网站,并将其作为观察者。当这个足球队的比赛结果出来后,官方网站就会向你发送通知,告诉你比赛的结果。
在这个例子中,足球队就是主题对象,而球迷就是观察者。球迷可以随时取消订阅,也可以同时订阅多个足球队的官方网站,这就体现了观察者模式中的松耦合性和可重用性。同时,足球队可以向所有订阅者广播比赛结果,这就体现了观察者模式中的广播通信特性。
总的来说,观察者模式就是一个对象(即主题)发生变化时,其他对象(即观察者)能得到通知并自动更新,从而实现对象之间的松耦合、可重用性和广播通信等特性。
4、代码示例
import java.util.ArrayList;
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}
interface Observer {
void update(String message);
}
class NewsPaper implements Subject {
private ArrayList<Observer> observers = new ArrayList<>();
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setNews(String news) {
System.out.println("今日新闻:" + news);
notifyObservers(news);
}
}
class Reader implements Observer {
private String name;
public Reader(String name) {
this.name = name;
}
public void update(String message) {
System.out.println(name + "收到新闻:" + message);
}
}
public class ObserverDemo {
public static void main(String[] args) {
NewsPaper newspaper = new NewsPaper();
Reader reader1 = new Reader("小明");
Reader reader2 = new Reader("小红");
newspaper.registerObserver(reader1);
newspaper.registerObserver(reader2);
newspaper.setNews("中国女排夺冠了!");
// 输出:
// 今日新闻:中国女排夺冠了!
// 小明收到新闻:中国女排夺冠了!
// 小红收到新闻:中国女排夺冠了!
}
}
在这个示例中,NewsPaper是主题接口,Reader是观察者接口。NewsPaper实现了主题接口,包含了注册、移除和通知观察者的方法。
Reader实现了观察者接口,包含了更新状态的方法。在main方法中,我们创建了一个NewsPaper对象和两个Reader对象,并将两个Reader对象注册到NewsPaper中。当NewsPaper的新闻发生改变时,它会通知所有的观察者,并调用它们的update方法。最终,输出结果表明两个Reader对象都收到了这条新闻。
class Subject {
constructor() {
this.observers = [];
}
registerObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
const index = this.observers.findIndex((o) => o === observer);
this.observers.splice(index, 1);
}
notifyObservers(message) {
for (const observer of this.observers) {
observer.update(message);
}
}
}
class NewsPaper extends Subject {
constructor() {
super();
this.news = "";
}
setNews(news) {
console.log(`今日新闻:${news}`);
this.news = news;
this.notifyObservers(news);
}
}
class Reader {
constructor(name) {
this.name = name;
}
update(message) {
console.log(`${this.name}收到新闻:${message}`);
}
}
const newspaper = new NewsPaper();
const reader1 = new Reader("小明");
const reader2 = new Reader("小红");
newspaper.registerObserver(reader1);
newspaper.registerObserver(reader2);
newspaper.setNews("中国女排夺冠了!");
// 输出:
// 今日新闻:中国女排夺冠了!
// 小明收到新闻:中国女排夺冠了!
// 小红收到新闻:中国女排夺冠了!
在这个示例中,Subject是主题类,包含了注册、移除和通知观察者的方法。NewsPaper继承自Subject,实现了设置新闻和记录新闻的功能。
Reader是观察者类,包含了更新状态的方法。在代码的最后,我们创建了一个NewsPaper对象和两个Reader对象,并将两个Reader对象注册到NewsPaper中。当NewsPaper的新闻发生改变时,它会通知所有的观察者,并调用它们的update方法。最终,输出结果表明两个Reader对象都收到了这条新闻。