观察者模式是一种常用的设计模式,它用于在对象之间建立一对多的关系,当一个对象状态发生改变时,它的所有依赖对象都会收到通知并自动更新。在 Java 中,观察者模式可以使用 Java 自带的 Observer 和 Observable 类来实现。本文将深入探讨 Java 中观察者模式的实现方式、优缺点,并提供相应的代码示例。
一、Java 中的观察者模式
在 Java 中,观察者模式可由两个类来实现:Observable(被观察者)和 Observer(观察者)。Observable 类维护一个观察者列表,当其状态发生改变时,会通知所有观察者。Observer 类则定义了一个更新接口,用于在被观察者状态发生改变时更新自身状态。
以下是 Observable 类的简单实现:
import java.util.Observable;
public class MyObservable extends Observable {
private String message;
public void setMessage(String message) {
this.message = message;
setChanged(); // 标记状态已改变
notifyObservers(message); // 通知所有观察者
}
}
在上述示例中,MyObservable 继承了 Java 自带的 Observable 类,并添加了一个 message 属性。当 message 属性发生改变时,MyObservable 会调用 setChanged() 方法标记状态已改变,并调用 notifyObservers() 方法通知所有观察者。以下是 Observer 类的简单实现:
import java.util.Observable;
import java.util.Observer;
public class MyObserver implements Observer {
private String name;
public MyObserver(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(name + " received message: " + arg);
}
}
在上述示例中,MyObserver 实现了 Observer 接口,用于在被观察者状态发生改变时更新自身状态。当 MyObserver 接收到被观察者发来的消息时,它将打印消息内容。
二、观察者模式的优缺点
观察者模式的优点在于解耦,被观察者与观察者之间的关系是松散的,它们之间仅通过接口进行交互。这意味着被观察者和观察者可以独立进行修改而不会影响到对方,同时也可以方便地添加或删除观察者。观察者模式也可以用于实现异步通知机制,提高程序的响应速度和可伸缩性。
观察者模式的缺点在于可能会导致性能问题,当观察者较多且被观察者状态频繁发生改变时,通知所有观察者可能会成为瓶颈。此外,观察者模式也可能引起循环引用的问题,需要谨慎处理。
三、示例代码
以下是一个完整的 Java 观察者模式示例代码:
import java.util.Observable;
import java.util.Observer;
public class ObserverPatternDemo {
public static void main(String[] args) {
MyObservable observable = new MyObservable();
MyObserver observer1 = new MyObserver("Observer 1");
MyObserver observer2 = new MyObserver("Observer 2");
observable.addObserver(observer1);
observable.addObserver(observer2);
observable.setMessage("Hello, World!");
}
}
class MyObservable extends Observable {
private String message;
public void setMessage(String message) {
this.message = message;
setChanged();
notifyObservers(message);
}
}
class MyObserver implements Observer {
private String name;
public MyObserver(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(name + " received message: " + arg);
}
}
在上述示例中,我们创建了一个 MyObservable 对象,并添加了两个观察者 observer1 和 observer2。当 MyObservable 的 message 属性发生改变时,它会通知所有观察者并打印消息内容。
总结
观察者模式是一种常用的设计模式,它可以用于在对象之间建立一对多的关系,当一个对象状态发生改变时,它的所有依赖对象都会收到通知并自动更新。在 Java 中,观察者模式可以使用 Java 自带的 Observer 和 Observable 类来实现。观察者模式的优点在于解耦,缺点在于可能会导致性能问题和循环引用的问题,需要谨慎使用。
四、观察者模式的应用场景
观察者模式在实际应用中非常常见,例如 GUI 框架、事件驱动机制、消息队列等都可以使用观察者模式。下面列举一些常见的应用场景:
- 消息通知机制:当某个对象的状态发生变化时,需要通知其它对象进行相应的处理,比如在 Android 中,当用户点击某个按钮时,需要通知 Activity 进行相应的处理。
- 订阅/发布模式:例如在微信公众号或者博客等平台中,用户可以订阅某个作者的文章,当作者发布新文章时,订阅者会收到通知。
- 聊天室:聊天室中的用户可以互相发送消息,当有新消息时,聊天室中所有的用户都会收到通知。
- 监听器模式:例如在 Java 中,使用监听器模式可以监听某个对象的事件,并在事件发生时执行相应的处理逻辑。
五、观察者模式和发布订阅模式的区别
观察者模式和发布订阅模式在实现方式上有些相似,但它们之间还是有一些区别的。
观察者模式中,被观察者和观察者之间是直接联系的,被观察者维护一个观察者列表,当状态发生变化时,主动通知所有的观察者。观察者模式中,观察者是知道被观察者的存在的,被观察者对观察者一无所知。
而在发布订阅模式中,发布者和订阅者之间是没有直接联系的,发布者将消息发布到主题中心,订阅者从主题中心订阅消息,当有消息发生时,主题中心会将消息发送给所有订阅者。发布订阅模式中,发布者和订阅者之间是通过主题中心进行联系的,它们之间是相互独立的。
六、总结
本文介绍了 Java 中观察者模式的实现方式和优缺点,并提供了相应的代码示例。观察者模式是一种常用的设计模式,可以用于在对象之间建立一对多的关系,当一个对象状态发生改变时,它的所有依赖对象都会收到通知并自动更新。观察者模式的优点在于解耦,缺点在于可能会导致性能问题和循环引用的问题,需要谨慎使用。观察者模式在实际应用中非常常见,例如 GUI 框架、事件驱动机制、消息队列等都可以使用观察者模式。同时,本文还介绍了观察者模式和发布订阅模式之间的区别,希望能够对读者有所帮助。
七、常见问题及解决方案
循环引用问题
在使用观察者模式时,如果被观察者和观察者出现循环引用,可能会导致内存泄漏等问题。解决这个问题的方法是使用弱引用(WeakReference)或者软引用(SoftReference)来存储观察者,当观察者被垃圾回收时,不会影响到被观察者的正常运行。
性能问题
在使用观察者模式时,如果观察者数量过多或者被观察者的状态变化频繁,可能会导致性能问题。解决这个问题的方法是采用异步通知的方式,即在被观察者的状态发生变化时,先将通知放入队列中,然后由另外的线程异步地进行通知,可以有效避免性能问题。
多线程问题
在多线程环境中,观察者模式需要考虑线程安全的问题,即在修改被观察者的状态时需要进行同步操作。可以使用 synchronized 或者 Lock 来实现同步。
八、参考资料
- 《设计模式:可复用面向对象软件的基础》(Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著,机械工业出版社,2007)
- 《Java核心技术卷I》(Cay S. Horstmann, Gary Cornell 著,机械工业出版社,2018)
- 《Effective Java》(Joshua Bloch 著,机械工业出版社,2018)