目录
1.常用场景
- 当一个对象状态的改变需要改变其他对象时。比如,商品库存数量发生变化时,需要通知商品详情页、购物车等系统改变数量。
- 一个对象发生改变时只想要发送通知,而不需要知道接收者是谁。比如,订阅微信公众号的文章,发送者通过公众号发送,订阅者并不知道哪些用户订阅了公众号。
- 需要创建一种链式触发机制时。比如,在系统中创建一个触发链,A 对象的行为将影响 B 对象,B 对象的行为将影响 C 对象……这样通过观察者模式能够很好地实现。
- 微博或微信朋友圈发送的场景。这是观察者模式的典型应用场景,一个人发微博或朋友圈,只要是关联的朋友都会收到通知;一旦取消关注,此人以后将不会收到相关通知。
- 需要建立基于事件触发的场景。比如,基于 Java UI 的编程,所有键盘和鼠标事件都由它的侦听器对象和指定函数处理。当用户单击鼠标时,订阅鼠标单击事件的函数将被调用,并将所有上下文数据作为方法参数传递给它。
2.观察者模式原理
- Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要与具体目标保持一致.
3.观察者模式实现
(1)抽象主题
public abstract class Subject {
List<Observer> observers;
Subject(){
observers = new ArrayList<Observer>();
}
// 添加观察者
public void addObserver(Observer observer){
observers.add(observer);
}
// 删除观察者
public void removeObserver(Observer observer){
observers.remove(observer);
}
// 通知观察者
public abstract void notifyObservers(Message message);
}
public class WorkSubject extends Subject {
@Override
public void notifyObservers(Message message) {
// 工作状态发生改变,通知所有观察者
for (Observer observer : observers) {
observer.process(message);
}
}
}
(2)观察者
public interface Observer {
void process(Message message);
}
public class PCObserver implements Observer {
private String name;
PCObserver(){
super();
name = "电脑端";
}
@Override
public void process(Message message) {
System.out.println("【"+name+"】收到消息:"+message.getMessage());
}
}
public class MobileObserver implements Observer {
private String name;
MobileObserver(){
super();
name = "手机端";
}
@Override
public void process(Message message) {
System.out.println("【"+name+"】收到消息:"+message.getMessage());
}
}
(3)测试类
public class Test {
public static void main(String[] args) {
Subject subject = new WorkSubject();
Observer pcObserver = new PCObserver();
Observer mobileObserver = new MobileObserver();
Message message = new Message("用户下线。。。。");
//添加观察者
subject.addObserver(pcObserver);
subject.addObserver(mobileObserver);
//通知观察者
subject.notifyObservers(message);
}
}
4.JDK中的观察者
(1)抽象观察者
java.util.Observer
接口: 该接口中声明了一个方法,它充当抽象观察者
(2)被观察类
java.util.Observable
类: 充当观察目标类(被观察类) , 在该类中定义了一个Vector集合来存储观察者对象.- void addObserver(Observer o) 方法:用于将新的观察者对象添加到集合中。
- void notifyObservers(Object arg) 方法:调用集合中的所有观察者对象的 update方法,通知它们数据发生改变。通常越晚加入集合的观察者越先得到通知。
- void setChange() 方法:用来设置一个 boolean 类型的内部标志,注明目标对象发生了变化。当它为true时,notifyObservers() 才会通知观察者。
(3)代码改造
public class WorkSubject extends Observable {
public void onMessage(Message message){
// 设置消息状态
setChanged();
// 通知所有观察者
notifyObservers(message);
}
}
//具体观察者
public class MobileObserver implements Observer {
private String name;
MobileObserver(){
super();
name = "手机端";
}
@Override
public void update(Observable o, Object arg) {
if (arg instanceof Message){
System.out.println(name+" 收到消息:"+((Message) arg).getMessage());
}
}
}
public class PCObserver implements Observer {
private String name;
PCObserver(){
super();
name = "电脑端";
}
@Override
public void update(Observable o, Object arg) {
if (arg instanceof Message){
System.out.println(name+" 收到消息:"+((Message) arg).getMessage());
}
}
}
//消息
public class Message {
private String message;
Message(String message){
this.message=message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
//测试类
public class Test {
public static void main(String[] args) {
WorkSubject subject = new WorkSubject();
Observer pcObserver = new PCObserver();
Observer mobileObserver = new MobileObserver();
Message message = new Message("用户下线。。。。");
//添加观察者
subject.addObserver(pcObserver);
subject.addObserver(mobileObserver);
//通知观察者
subject.onMessage(message);
}
}
5.优缺点
(1)优点
- 松耦合和高扩展性:观察者和被观察者之间的耦合是抽象的,这允许系统更容易地扩展和修改。增加新的观察者或修改被观察者的行为时,不需要修改已有的代码。
- 自动触发机制:当被观察对象的状态发生变化时,系统可以自动通知所有注册的观察者,这简化了事件处理和状态更新的过程。
- 符合开闭原则:这一设计原则要求软件实体对扩展开放,对修改关闭。观察者模式支持这一原则,因为可以在不修改现有代码的情况下添加新的功能。
(2)缺点
- 性能问题:当存在大量的观察者时,通知所有这些观察者可能会成为性能瓶颈,特别是当每个观察者都需要花费较多时间处理通知时。
- 循环依赖问题:如果观察者和被观察者之间存在循环依赖,这可能导致在通知过程中出现循环调用,从而引发系统崩溃或不稳定。
- 缺乏对变化细节的了解:观察者模式主要通知观察者目标对象的状态已经改变,但不提供关于如何或为什么会发生这种变化的信息。