观察者模式 - 由浅到更浅

前言

关于观察者模式,经常提及,其实我们在项目开发过程中也经常用到,但是对于这个 东西一直不是很明朗,今天找了些资料做了个整理。以下是我对观察者模式的理解。

我认为,观察者模式在实际运用中,绝大多数的情况都会牵扯到接口回调的结合使用。其中最明显的例子就是安卓开发中的点击事件。以button为例,当点击动作发生的时候,会立即走到点击事件监听的onClick方法中。这个现象不难理解,那么他是怎么实现的呢?

首先触发者,也就是用户,与被触发者,按钮。这两者之间必然存在着一种即时的关系。什么叫即时?就是你打我一下我立马感觉到疼,因为动作触发的那一刹那,神经与皮肤之间存在这关联,可以立马感知到这个结果。

以上是我结合生活中的实例,举的一个很浅显的例子。如果还不懂的话,可以找个人多打你几次试试。

解析

根据所找到的资料显示,观察者模式是一种一对多的即时关系,以上所举的例子都是一对一,一对一也算是一对多的一种。

那么在这个过程中,需要有两个对象概念,观察者,被观察者;以上的例子其实还不完善,有一个比较经典的例子就是警察抓小偷,首先,警察是观察者,小偷是被观察者,如果小偷要偷东西,那么警察肯定会立马作出反应去抓他。之所以说这个例子比较经典,是因为,在小偷偷东西的一刹那,警察对于偷的动作具有高度敏感性,从而立马去作出反应。因此,这种关系常常作为观察者模式中一种比较经典的案例。

以上说到两个概念,观察者,被观察者【也被称作主体】,通常在代码中为了实现一对多的关系,需要多层封装,也就是最底层用interface来实现,那么这样的观察者被称为抽象观察者,这样的被观察者成为抽象被观察者,或抽象主体。

抽象观察者


public interface BaseObserver {

    void update(String info);

}

抽象被观察者【抽象主体】


public interface BaseSubject {

    //注册行为
    void subscribe(BaseObserver observer);

    //解注册行为
    void unSubscribe(BaseObserver observer);

    //通知观察者
    void notify2Observer(String info);

}

首先看到,如果你要实现观察者模式,也就是警察抓小偷的功能时,需要注意。两者之间首先需要通过注册形成关联,也就是,警察与小偷的身份是怎么形成的。这个方法需要在被观察者中实现,这里的注册功能就是subscribe方法。同时在真正的实践应用中,你还可以进行解绑行为,也就是这里的unSubscribe方法【当然这里不要生搬硬套警察抓小偷】,同时,还有一个触发动作的方法,也就是小偷的偷东西行为,这里就是notify2Observer方法。

那么我们来看具体实现

观察者1


public class Observer1 implements BaseObserver {

    private OnGetInfoFromSubjectListener listener;

    @Override
    public void update(String info) {
        if (listener != null) {
            listener.onGetInfo(info + "observer1");
        }
    }

    public void setOnGetInfoFromSubjectListener(OnGetInfoFromSubjectListener listener) {
        this.listener = listener;
    }
}

观察者2


public class Observer2 implements BaseObserver {

    private OnGetInfoFromSubjectListener listener;

    @Override
    public void update(String info) {
        if (listener != null) {
            listener.onGetInfo(info + "observer2");
        }
    }

    public void setOnGetInfoFromSubjectListener(OnGetInfoFromSubjectListener listener) {
        this.listener = listener;
    }

}

注:这里我手动写了一个接口回调用于向外部暴露数据

被观察者【主体】


public abstract class Subject implements BaseSubject {

    private ArrayList<BaseObserver> mObserverList = new ArrayList<>();

    @Override
    public void subscribe(BaseObserver observer) {
        mObserverList.add(observer);
    }

    @Override
    public void unSubscribe(BaseObserver observer) {
        mObserverList.remove(observer);
    }

    @Override
    public void notify2Observer(String info) {
        for (BaseObserver observer : mObserverList) {
            observer.update(info);
        }
    }
}

最终对外部暴露的被观察者


public class RealSubject extends Subject {

    private String mInfo = "I am a subject and was subscribed by ~ ";

    public void sendInfo2Observer() {
        notify2Observer(mInfo);
    }

}

之前已经讲过,首先要实现这些功能,第一部要进行注册,然后再去更新数据进行通知。为了让这个过程更具体,我写了一个界面。

第一步点击subscribe,第二步点击notify,即可看到数据立马显示在屏幕上。

那么首页的代码


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView mTvInfoFromObserver1;
    private TextView mTvInfoFromObserver2;
    private Button mBtnSubscribe;
    private Button mBtnNotify;

    private RealSubject mRealSubject;
    private Observer1 mObserver1;
    private Observer2 mObserver2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        initView();
        initAction();
        initData();
    }

    private void initData() {
        if (mRealSubject == null) {
            mRealSubject = new RealSubject();
        }
        if (mObserver1 == null) {
            mObserver1 = new Observer1();
            mObserver1.setOnGetInfoFromSubjectListener(new OnGetInfoFromSubjectListener() {
                @Override
                public void onGetInfo(String info) {
                    mTvInfoFromObserver1.setText(info);
                }
            });
        }
        if (mObserver2 == null) {
            mObserver2 = new Observer2();
            mObserver2.setOnGetInfoFromSubjectListener(new OnGetInfoFromSubjectListener() {
                @Override
                public void onGetInfo(String info) {
                    mTvInfoFromObserver2.setText(info);
                }
            });
        }
    }

    private void initAction() {
        mBtnSubscribe.setOnClickListener(this);
        mBtnNotify.setOnClickListener(this);
    }

    private void initView() {
        mTvInfoFromObserver1 = (TextView) findViewById(R.id.tv_info_from_observer1);
        mTvInfoFromObserver2 = (TextView) findViewById(R.id.tv_info_from_observer2);
        mBtnSubscribe = (Button) findViewById(R.id.btn_subscribe);
        mBtnNotify = (Button) findViewById(R.id.btn_notify);
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == mBtnSubscribe.getId()) {
            mRealSubject.subscribe(mObserver1);
            mRealSubject.subscribe(mObserver2);
        }
        if (id == mBtnNotify.getId()) {
            mRealSubject.sendInfo2Observer();
        }
    }
}

然后源码传送门
观察者模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值