初衷 :因架构(开发)场景(需求)而使用设计模式,莫为了使用设计模式而设计架构场景!
设计模式共23种,分为三种类型
- 创建型模式:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
- 结构型模式:代理模式、装饰模式、外观模式、享元模式、桥接模式、组合模式、适配器模式
- 行为型模式:观察者模式、策略模式、中介者模式、模版方法模式、命令模式、迭代器模式、职责链模式(责任链模式)、备忘录模式、解释器模式(Interpreter模式)、状态模式、访问者模式
基本概念
观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知
应用场景
- 当一个对象更新状态的时候,与其绑定的对象可同步更新,同时绑定对象的数量动态可变
- 当前对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节
角色分配
抽象主题( 被观察者 )- Subject
将所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者
抽象主题提供一个接口,可以增加、删除观察者对象,同时向观察者发送通知
具体主题( 被观察者 )- ConcreteSubject
将相关状态存入具体主题对象;
在具体主题内部状态改变时,给所有绑定过的观察者发出通知
象观察者 - Observer
为所有的具体观察者定义一个接口,在得到主题通知时更新自己
具体观察者 - ConcreteObserver
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调
优缺点
优点
- 被观察者与观察者关联之后,被观察者仅知观察者拥有一个共同接口,从而达到了松耦合的关系
- 观察者模式支持广播通讯,被观察者会向所有的登记过的观察者发出通知
缺点
- 当被观察者绑定的观察者越来越多,在被观察者发送消息时耗时增大
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间 - 循环依赖,循环调用可能会导致OOM,从而系统崩溃
如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点 - 观察者只知通知已到,未知被观察者的具体实现
虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的
观察者模式&发布/订阅模式区别
有人喜欢把观察者模式叫做发布/订阅模式,但是从本质上是有所区别的 ~
角色方面
观察者模式里,只有两个角色 — 观察者 + 被观察者
而发布订阅模式里,却不仅仅只有发布者和订阅者两个角色,还有一个经常被我们忽略的 — 中间人
耦合状态
观察者和被观察者,是松耦合的关系
发布者和订阅者,则完全不存在耦合
使用层面
观察者模式,多用于单个应用内部
发布订阅模式,则更多的是一种跨应用的模式(cross-application pattern),比如我们常用的消息中间件
注意事项
- 避免循环引用
- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式
如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的
辅助理解
结构图
思维图(Demo图)
Demo思维
注:被观察者可以被N个观察者绑定
- 某明星的微博作为被观察者,粉丝关注某明星之后作为该明星的观察者
- 当明星发微博的时候,会通知粉丝此条微博信息
- 粉丝在获取接收到此条信息的时候,可以操作,如转发、评论等
模拟代码
//被观察者 - 明星诞生
StarSubject star= new StarSubject();
//观察者 - 粉丝诞生
Observer_FansA fansA = new Observer_FansA();
//观察者观察被观察者(被观察者绑定观察者)- 相当于粉丝关注明星的操作(明星被关注)
star.addObserver(fansA)
//被观察者通知观察者最新状态 - 明星发微博后通知到粉丝
star.notifyObserver("今天好想发个微博");
//关于粉丝的接听到微博信息后做的操作一般都在粉丝的内部类下,如以下模拟
class Observer_FansA implements Observer {
@Override
public void update(String data) {
Log.e("tag", "Observer_FansA观察到:" + data);
}
}
//最终结果输入内容为
tag: Observer_FansA观察到:今天好想发个微博
实战场景
被观察者
抽象主题 - Subject
package nkwl.com.observerdemo;
/**
* @author MrLiu
* @date 2020/1/6
* desc
*/
public interface Subject {
void addObserver(Observer observer);
void delObserver(Observer observer);
void notifyObserver(String result);
}
具体主题 - ConcreteSubject
package nkwl.com.observerdemo;
import java.util.ArrayList;
import java.util.List;
/**
* @author MrLiu
* @date 2020/1/6
* desc
*/
public class ConcreteSubject implements Subject {
private List<Observer> observeList = new ArrayList<Observer>();
public void addObserver(Observer observer) {
observeList.add(observer);
}
public void delObserver(Observer observer) {
observeList.remove(observer);
}
public void notifyObserver(String result) {
for (Observer o : observeList) {
o.update(result);
}
}
}
使用场
观察者
抽象观察者 - Observer
package nkwl.com.observerdemo;
/**
* @author MrLiu
* @date 2020/1/6
* desc
*/
public interface Observer {
void update(String data);
}
具体观察者 - Observer_FansA
package nkwl.com.observerdemo;
import android.util.Log;
/**
* @author MrLiu
* @date 2020/1/6
* desc
*/
public class Observer_FansA implements Observer {
@Override
public void update(String data) {
Log.e("tag", "Observer_FansA观察到:" + data);
}
}
具体观察者 - Observer_FansB
package nkwl.com.observerdemo;
import android.util.Log;
/**
* @author MrLiu
* @date 2020/1/6
* desc
*/
public class Observer_FansB implements Observer {
@Override
public void update(String data) {
Log.e("tag", "Observer_FansB观察到:" + data);
}
}
具体观察者 - Observer_FansC
package nkwl.com.observerdemo;
import android.util.Log;
/**
* @author MrLiu
* @date 2020/1/6
* desc
*/
public class Observer_FansC implements Observer {
@Override
public void update(String data) {
Log.e("tag", "Observer_FansC观察到:" + data);
}
}
场景类(使用场景)
因为主责是Android端,故我使用的是 MainActivity 为主入口,不影响理解使用 ~
package nkwl.com.observerdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//被观察者
ConcreteSubject subject = new ConcreteSubject();
//观察者
Observer_FansA a = new Observer_FansA();
Observer_FansB b = new Observer_FansB();
Observer_FansC c = new Observer_FansC();
//观察者观察被观察者(被观察者绑定观察者)
subject.addObserver(a);
subject.addObserver(b);
subject.addObserver(c);
//被观察者通知观察者最新状态
subject.notifyObserver("今天好想发个微博");
}
}