Java 观察者模式

本文我们介绍观察者模式,通过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 方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值