Skip to main content
 首页 » 编程设计

Java 观察者模式

2022年07月19日163Terrylee

本文我们介绍观察者模式,通过Java语言提供多种方法实现。

什么是观察者模式

观察者模式属于行为设计模式,用于对象之间交互:可观察对象和观察者。可观察对象当其状态发生变化时通知观察者。举例,新闻机构收到新闻时通知频道,接收新闻表示新闻机构的状态发生了变化,触发频道接收通知。

下面看如何实现。首先定义新闻机构:

public class NewsAgency {
    
    private String news; 
    private List<Channel> channels = new ArrayList<>(); 
 
    public void addObserver(Channel channel) {
    
        this.channels.add(channel); 
    } 
 
    public void removeObserver(Channel channel) {
    
        this.channels.remove(channel); 
    } 
 
    public void setNews(String news) {
    
        this.news = news; 
        for (Channel channel : this.channels) {
    
            channel.update(this.news); 
        } 
    } 
} 

NewsAgency 是可观察对象,当有新闻更新时,它的状态变化了;新闻机构通过调用update()方法通知观察者这个事实。要实现该功能,可观察对象需要持有观察者的引用,上面示例为channels变量。

现在我们看观察者,Channel类,它应该有update方法,当 NewsAgency 状态变化时调用该方法。

public class NewsChannel implements Channel {
    
    private String news; 
 
    @Override 
    public void update(Object news) {
    
        this.setNews((String) news); 
    }  
} 

Channel接口仅有一个方法。

public interface Channel {
    
    public void update(Object o); 
} 

现在如果增加 NewsChannel至观察者列表,改变 NewsAgency状态, NewsChannel实例会调用update方法:

NewsAgency observable = new NewsAgency(); 
NewsChannel observer = new NewsChannel(); 
 
observable.addObserver(observer); 
observable.setNews("news"); 
assertEquals(observer.getNews(), "news"); 

java 核心库中已经预定义了 Observer 接口,利用它实现观察者模式会更简单,下面看看如何利用。

利用 Observer 接口实现

java.util.Observer接口定义了update方法,所以无需定义前一节的接口。下面看如何使用

public class ONewsChannel implements Observer {
    
 
    private String news; 
 
    @Override 
    public void update(Observable o, Object news) {
    
        this.setNews((String) news); 
    } 
} 

第二个参数来自Observable对象,请继续往下浏览:

为了定义可观察者对象,需要继承 Observable 类:

public class ONewsAgency extends Observable {
    
    private String news; 
 
    public void setNews(String news) {
    
        this.news = news; 
        setChanged(); 
        notifyObservers(news); 
    } 
} 

注意我们不需要直接调用 update 方法,仅需要调用 setChanged()notifyObservers() 方法,剩下的事情有 Observable 类负责。

同样它也维护一组观察者,并暴露方法维护该列表—— addObserver()deleteObserver() 。为了测试结果,我们需要增加观察者至列表并设置新闻:

ONewsAgency observable = new ONewsAgency(); 
ONewsChannel observer = new ONewsChannel(); 
 
observable.addObserver(observer); 
observable.setNews("news"); 
assertEquals(observer.getNews(), "news"); 

Observer 接口从java 9 开始已不建议使用 (标记为 deprecated )。其中一个问题是 Observable 不是接口而是类,这就是为什么子类不能作为Observable使用的原因。另外开发者可能会覆盖Observable 的同步方法破坏了线程安全。

下面我们看 PropertyChangeListener 接口,它被推荐待用 Observer 。

利用 PropertyChangeListener 实现

该方法可观测对象必须持有 PropertyChangeListener 实例,当类属性变化是用其发送通知给观察者。

public class PCLNewsAgency {
    
    private String news; 
 
    private PropertyChangeSupport support; 
 
    public PCLNewsAgency() {
    
        support = new PropertyChangeSupport(this); 
    } 
 
    public void addPropertyChangeListener(PropertyChangeListener pcl) {
    
        support.addPropertyChangeListener(pcl); 
    } 
 
    public void removePropertyChangeListener(PropertyChangeListener pcl) {
    
        support.removePropertyChangeListener(pcl); 
    } 
 
    public void setNews(String value) {
    
        support.firePropertyChange("news", this.news, value); 
        this.news = value; 
    } 
} 

使用该方法,也可以增加或删除观察者,当可观察对象状态变化是发送通知:

support.firePropertyChange("news", this.news, value); 

第一个参数是属性名称,后面两个参数分别是原值和新值。观察者需要实现 PropertyChangeListener 接口:

public class PCLNewsChannel implements PropertyChangeListener { 
 
    private String news; 
 
    public void propertyChange(PropertyChangeEvent evt) { 
        this.setNews((String) evt.getNewValue()); 
    } 
} 

由于 propertychangessupport 类是我们自己实现,故可以从事件中获取新的属性值。下面测试看结果:

PCLNewsAgency observable = new PCLNewsAgency(); 
PCLNewsChannel observer = new PCLNewsChannel(); 
 
observable.addPropertyChangeListener(observer); 
observable.setNews("news"); 
 
assertEquals(observer.getNews(), "news"); 

总结

本文介绍了观察者模式,在Java中提供三种方式进行实现,其中推荐使用 PropertyChangeListener 方法。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/118163356
阅读延展