1. 观察者模式
观察者模式是一种设计模式,它允许一个对象(主题)维护一组依赖于它的对象(观察者)并在状态发生变化时通知它们。这种模式属于行为型模式。在观察者模式中,主题是被观察的对象,而观察者是依赖于主题的对象,当主题的状态发生变化时,所有注册的观察者都会得到通知并自动更新。
以下是观察者模式的主要角色:
- 主题(Subject): 主题是被观察的对象,它维护一组观察者并通知它们状态的变化。主题可以有添加、删除观察者的方法。
- 观察者(Observer): 观察者是依赖于主题的对象,当主题的状态发生变化时,观察者得到通知并执行相应的操作。
2. 关键思想
观察者模式的关键思想是定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者都会得到通知并被自动更新。这种方式实现了对象之间的松耦合,使得主题和观察者可以独立变化而互不影响。
以下是观察者模式的关键思想:
- 主题(Subject)维护观察者列表: 主题对象内部维护了一个观察者列表,该列表存储了所有依赖于该主题的观察者对象。
- 观察者(Observer)定义更新接口: 观察者对象实现一个更新接口,该接口通常包含一个参数,用于接收主题对象传递的状态信息。
- 注册和通知机制: 观察者通过注册(添加)到主题对象,主题对象在状态变化时通过通知机制来通知所有观察者。
- 松耦合: 主题和观察者之间是松耦合的关系,主题并不需要知道观察者的具体类型,而是依赖于观察者接口,这使得系统更容易扩展和维护。
- 广播通知: 当主题状态发生变化时,它会向所有注册的观察者广播通知,观察者接收通知后执行相应的更新操作。
观察者模式的应用场景包括但不限于:用户界面事件处理、分布式事件系统、消息队列系统等。这种模式能够有效地实现对象间的解耦,提高系统的灵活性和可维护性。
3. 实现方式
观察者模式的实现方式主要涉及到主题(Subject)和观察者(Observer)的接口定义以及它们的具体实现。以下是一个基本的观察者模式的实现方式:
- 主题接口(Subject):
// 主题接口,被观察者 public interface Subject { // 添加观察者到观察者列表 void addObserver(Observer observer); // 从观察者列表中移除观察者 void removeObserver(Observer observer); // 通知所有注册的观察者,主题状态发生变化 void notifyObservers(); }
- 观察者接口(Observer):
// 观察者接口,用于定义观察者的通用行为 public interface Observer { // 当被观察的主题状态发生变化时,观察者会被通知并调用该方法进行更新 void update(String state); // 通常包含一个参数,表示主题状态的变化 }
- 具体主题类(ConcreteSubject):
import java.util.ArrayList; import java.util.List; // 具体主题类,实现了Subject接口 public class ConcreteSubject implements Subject { // 观察者列表,存储所有注册的观察者 private List<Observer> observers = new ArrayList<>(); // 主题的状态 private String state; // 添加观察者到观察者列表 public void addObserver(Observer observer) { observers.add(observer); } // 从观察者列表中移除观察者 public void removeObserver(Observer observer) { observers.remove(observer); } // 通知所有注册的观察者,主题状态发生变化 public void notifyObservers() { for (Observer observer : observers) { observer.update(state); } } // 设置主题的状态,并通知观察者 public void setState(String state) { this.state = state; notifyObservers(); } }
这个类实现了观察者模式的主题接口,包括添加、移除观察者以及通知观察者的方法。当主题状态发生变化时,通过 notifyObservers 方法通知所有注册的观察者,并调用它们的 update 方法进行状态更新。
- 具体观察者类(ConcreteObserver):
// 具体观察者类,实现了Observer接口 public class ConcreteObserver implements Observer { // 观察者的状态,与主题的状态保持同步 private String observerState; // 当被观察的主题状态发生变化时,更新观察者的状态 public void update(String state) { observerState = state; System.out.println("Observer state updated: " + observerState); } }
这个类实现了观察者模式的观察者接口,包括了 update 方法,用于在被观察的主题状态发生变化时更新观察者的状态。在这个示例中,更新操作是简单地将观察者的状态与主题的状态保持同步,并输出更新信息到控制台。
- 示例用法:
// 示例类,演示观察者模式的使用 public class ObserverPatternExample { public static void main(String[] args) { // 创建一个具体主题对象 ConcreteSubject subject = new ConcreteSubject(); // 创建两个具体观察者对象 ConcreteObserver observer1 = new ConcreteObserver(); ConcreteObserver observer2 = new ConcreteObserver(); // 将观察者注册到主题对象 subject.addObserver(observer1); subject.addObserver(observer2); // 设置主题的状态,并触发观察者的更新 subject.setState("New State 1"); // Output: // Observer state updated: New State 1 // Observer state updated: New State 1 // 设置主题的状态,并触发观察者的更新 subject.setState("New State 2"); // Output: // Observer state updated: New State 2 // Observer state updated: New State 2 } }
这个示例创建了一个具体主题 ConcreteSubject,以及两个具体观察者 ConcreteObserver。观察者被注册到主题上,然后通过设置主题的状态,触发了观察者的更新操作。每个观察者通过 update 方法接收并处理主题的状态变化,输出了相应的更新信息。
示例代码:
考虑一个社交媒体平台的通知系统。在这个例子中,社交媒体平台充当主题,而用户是观察者。当有新的消息、点赞、评论等活动发生时,社交媒体平台会通知所有关注者。
import java.util.ArrayList; import java.util.List; // 主题接口 - 社交媒体平台 interface SocialMediaPlatform { // 添加观察者到关注列表 void addObserver(UserObserver observer); // 从关注列表中移除观察者 void removeObserver(UserObserver observer); // 通知所有关注者,传递最新的社交媒体活动 void notifyFollowers(String activity); } // 观察者接口 - 用户 interface UserObserver { // 当社交媒体平台发布新的活动时,更新用户的通知 void update(String activity); } // 具体主题类 - 具体的社交媒体平台 class ConcreteSocialMediaPlatform implements SocialMediaPlatform { // 关注社交媒体平台的用户列表 private List<UserObserver> followers = new ArrayList<>(); // 最新的社交媒体活动 private String latestActivity; // 添加用户到关注列表 public void addObserver(UserObserver observer) { followers.add(observer); } // 从关注列表中移除用户 public void removeObserver(UserObserver observer) { followers.remove(observer); } // 通知所有关注者,传递最新的社交媒体活动 public void notifyFollowers(String activity) { latestActivity = activity; for (UserObserver follower : followers) { follower.update(latestActivity); } } // 模拟有新的社交媒体活动发生,并通知所有关注者 public void postActivity(String activity) { notifyFollowers(activity); } } // 具体观察者类 - 用户 class User implements UserObserver { // 用户名 private String username; // 构造函数,初始化用户对象时需要指定用户名 public User(String username) { this.username = username; } // 当社交媒体平台发布新的活动时,更新用户的通知 public void update(String activity) { System.out.println(username + " 收到通知: " + activity); } } // 示例 public class SocialMediaPlatformExample { public static void main(String[] args) { // 创建具体社交媒体平台对象 ConcreteSocialMediaPlatform socialMediaPlatform = new ConcreteSocialMediaPlatform(); // 创建两个用户 User user1 = new User("Alice"); User user2 = new User("Bob"); // 用户关注社交媒体平台 socialMediaPlatform.addObserver(user1); socialMediaPlatform.addObserver(user2); // 模拟社交媒体平台发布新的活动 socialMediaPlatform.postActivity("管理员发布了新的动态"); // 输出: // Alice 收到通知: 管理员发布了新的动态 // Bob 收到通知: 管理员发布了新的动态 } }
在这个例子中,ConcreteSocialMediaPlatform 充当主题,而 User 充当观察者。当社交媒体平台发布新的活动时,所有关注者都会收到通知并更新。这个例子展示了观察者模式在社交媒体通知系统中的应用。
要点:
- 定义对象间一对多的依赖关系:观察者模式建立了一个一对多的依赖关系,使得一个主题对象的状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。
- 松耦合:主题和观察者之间的关系是松耦合的。主题不需要知道观察者的具体类,只需要知道它们实现了相同的接口。
- 适用于多个对象关心一个对象状态的情况:当一个对象的状态发生变化需要通知其他多个对象时,观察者模式是一个合适的选择。
- 支持广播通信:主题对象可以轻松地通知所有注册的观察者,实现了广播通信的能力。
注意事项:
- 避免循环依赖:注意在设计中避免循环依赖,以免引起不必要的复杂性。
- 避免观察者影响主题:观察者的更新操作应该尽量简洁,不要对主题对象产生太大的影响。
- 性能问题:如果观察者的数量很大,或者观察者的更新操作比较耗时,可能会影响整体性能。可以考虑异步方式来处理观察者的更新。
- Java内置支持:在Java中,观察者模式已经内置在java.util包中的Observer和Observable类中,但注意Observable类在Java 9及更高版本中被标记为过时(deprecated),建议使用其他方式实现观察者模式,比如使用接口和列表。
优点:
- 松耦合:主题和观察者之间是松耦合的关系,使得它们可以独立演化。主题对象不需要知道观察者的具体实现,只需要知道观察者实现了相应的接口。
- 扩展性好:可以在系统中方便地增加新的观察者,无需修改主题的代码。
- 可重用性:可以重用已有的观察者和主题类,使得系统更加灵活。
- 广播通信:主题对象可以方便地通知所有注册的观察者,实现广播通信。
缺点:
- 通知顺序不确定:观察者收到通知的顺序是不确定的,可能会导致一些潜在的问题。
- 可能导致性能问题:如果观察者的数量很大,或者观察者的更新操作比较耗时,可能会影响整体性能。
- 观察者感知主题状态的方式有限:观察者模式只能让观察者知道主题状态发生了变化,但不能获取变化的具体内容,除非主题对象在通知时主动传递。
应用场景:
- 事件处理系统:当一个事件发生时,多个对象需要对该事件进行响应,例如GUI界面的按钮、菜单、窗口等。
- 分布式系统中的消息推送:在分布式系统中,观察者模式可用于实现消息的推送,当一个节点的状态发生变化时,通知其他节点。
- 报警系统:报警系统中,监控器可以是观察者,被监测的设备是主题,当设备发生异常时,监控器收到通知并进行处理。
- 多层架构中的事件处理:在多层架构中,观察者模式可以用于处理不同层之间的事件通知,如业务逻辑层通知数据访问层进行数据更新。
- 发布-订阅模型:观察者模式可以用于实现发布-订阅模型,其中订阅者(观察者)订阅某个主题,当主题发生变化时,通知所有订阅者。