Java模式笔记之观察者模式

本文介绍了观察者模式的概念、UML图、应用场景及简单实现。通过示例解释了如何利用观察者模式实现对象间的依赖关系,当一个对象状态改变时,所有依赖对象能够自动更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是观察者模式?

观察者模式:对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并被自动更新。

观察者模式又称为发布——订阅者模式,根据这个名字来理解上面的一句话或许更好理解。观察者模式属于行为型设计模式。


二、观察者模式的UML图


观察者模式的角色介绍
Subject:抽象主题,也就是被观察者的角色,它把所有观察者对象保存在一个集合中。抽象主题提供了一个接口,用来增删观察者对象。
ConcreteSubject:具体主题,将有关状态存入具体观察者对象,在内部状态发生改变的时候,给所有注册过的观察者发送通知。
Observer:抽象观察者,定义了一个更新接口,得到Subject更改通知时更改自己。
ConcreteObserver:具体观察者,收到通知后更新自身的状态。

下面是另一种结构,来自于MOOC

观察者模式的结构和说明


三、为什么要使用观察者模式,什么地方使用它?

使用观察者模式的原因可以简单记为——解耦!使用观察者模式,使得被观察者和观察者之间的依赖很小,甚至于无依赖。比如Android开发中的UI层和具体业务逻辑层,如果可以做到无依赖,那么当我们需要更换UI界面的时候,具体业务层逻辑完全不需要修改。

观察者模式的使用场景:

  • 关联行为场景,需要注意的是,关联行为是可拆分的,而不是组合关系;
  • 事件多级触发场景;
  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制。

上面的这三行话,可能理解起来有些迷糊,也可以这样来记住:

  • 当一个对象的改变需要同时改变其他对象的时候;
  • 而且不知道具体有多少对象等待改变的时候,考虑使用观察者模式


四、观察者模式的简单实现

1.具体观察者

/**
 * 程序员是观察者
 * Observer是JDK中的内置类型,是抽象的观察者角色,即Observer
 * 那么Coder就是具体的观察者
 */

public class Coder implements Observer{
    public String name;

    public Coder(String aName){
        name = aName;
    }


    @Override
    public void update(Observable observable, Object data) {
        Log.d("zsf","您好," + name + ",您订阅的内容更新了!内容:" + data);
    }

    @Override
    public String toString() {
        return "码农:" + name;
    }
}

2.具体被观察者

/**
 * DevTechFrontier是被观察者,它有更新时,所有的Coder都会接到相应的通知
 * Observable是JDK中内置的类型,这里是抽象的主题,即Subject
 */

public class DevTechFrontier extends Observable {


    public void postNewPublication(String content){
        //标识状态或者内容发生改变
        setChanged();
        //通知所有观察者
        notifyObservers(content);
    }

}

3.客户端代码测试:

public class SubjectObserverTestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //被观察者角色
        DevTechFrontier devTechFrontier = new DevTechFrontier();

        //观察者
        Coder oneCoder = new Coder("程序员1");
        Coder twoCoder = new Coder("程序员2");
        Coder threeCoder = new Coder("程序员3");
        Coder fourthCoder = new Coder("程序员4");

        //将观察者注册到可观察对象的观察列表中
        devTechFrontier.addObserver(oneCoder);
        devTechFrontier.addObserver(twoCoder);
        devTechFrontier.addObserver(threeCoder);
        devTechFrontier.addObserver(fourthCoder);

        //发布消息
        devTechFrontier.postNewPublication("新一期的科技报发布了!");
    }
}

4.Log日志输出

04-06 18:32:46.873 8116-8116/? D/zsf: 您好,程序员1,您订阅的内容更新了!内容:新一期的科技报发布了!
04-06 18:32:46.873 8116-8116/? D/zsf: 您好,程序员2,您订阅的内容更新了!内容:新一期的科技报发布了!
04-06 18:32:46.873 8116-8116/? D/zsf: 您好,程序员3,您订阅的内容更新了!内容:新一期的科技报发布了!
04-06 18:32:46.873 8116-8116/? D/zsf: 您好,程序员4,您订阅的内容更新了!内容:新一期的科技报发布了!

Android中具体使用该模式的比如常用的ListView,每当需要更新内容的时候,我们会调用notifyDataSetChanged()方法。

源码:

/**
 * Common base class of common implementation for an {@link Adapter} that can be
 * used in both {@link ListView} (by implementing the specialized
 * {@link ListAdapter} interface) and {@link Spinner} (by implementing the
 * specialized {@link SpinnerAdapter} interface).
 */
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();//数据集观察者

    public boolean hasStableIds() {
        return false;
    }
    
    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }
    
    /**
     * Notifies the attached observers that the underlying data has been changed
     * and any View reflecting the data set should refresh itself.
     * 数据集变化时,通知所有观察者
    */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    /**
     * Notifies the attached observers that the underlying data is no longer valid
     * or available. Once invoked this adapter is no longer valid and should
     * not report further data set changes.
     */
    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }

    public boolean areAllItemsEnabled() {
        return true;
    }

    public boolean isEnabled(int position) {
        return true;
    }

    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getView(position, convertView, parent);
    }

    public int getItemViewType(int position) {
        return 0;
    }

    public int getViewTypeCount() {
        return 1;
    }
    
    public boolean isEmpty() {
        return getCount() == 0;
    }
}

五、观察者模式的不足

需要考虑开发效率和运行效率,一个被观察者通知多个观察者,开发和调试困难增加;Java中消息的通知默认采用顺序执行,一个观察者卡顿,整体效率降低,这时考虑使用异步解决。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值