观察者模式
来源:互联网 发布:单片机如何烧程序 编辑:程序博客网 时间:2024/06/15 10:31
前言
关于观察者模式,经常提及,其实我们在项目开发过程中也经常用到,但是对于这个 东西一直不是很明朗,今天找了些资料做了个整理。以下是我对观察者模式的理解。
我认为,观察者模式在实际运用中,绝大多数的情况都会牵扯到接口回调的结合使用。其中最明显的例子就是安卓开发中的点击事件。以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(); } }}
然后源码传送门
观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- JS中从Array.slice()与Array.splice()的底层实现原理分析区别
- HTTP协议理解
- 字母次数
- 如何编写测试计划
- 加农炮
- 观察者模式
- 41. First Missing Positive
- 自定义控件(三种)
- Ajax 知识地址总汇
- Android BLE Gatt返回错误对应宏
- Virtual Friends(普通的并查集)
- SVN 使用简介及个人总结
- pip命令显示不是内部或外部命令,也不是可运行的程序或批处理文件
- Myeclipse运行程序时,发生异常:Exception in thread ""http-bio-8080"-exec-1" java.lang.OutOfMemoryError: PermGen