系列文章目录
创建型模式 - 单例模式(一)
创建型模式 - 工厂模式(二)
创建型模式 - 原型模式(三)
创建型模式 - 建造者模式(四)
结构型模式 - 适配器模式(一)
结构型模式 - 桥接模式(二)
结构型模式 - 装饰器模式(三)
结构型模式 - 组合模式(四)
结构型模式 - 外观模式(五)
结构型模式 - 享元模式(六)
结构型模式 - 代理模式(七)
行为型模式 - 模板方法模式(一)
行为型模式 - 命令模式(二)
行为型模式 - 访问者模式(三)
行为型模式 - 迭代器模式(四)
行为型模式 - 观察者模式(五)
行为型模式 - 中介者模式(六)
行为型模式 - 备忘录模式(七)
行为型模式 - 解释器模式(八)
行为型模式 - 状态模式(九)
行为型模式 - 策略模式(十)
行为型模式 - 责任链模式(十一)
文章目录
前言
一、观察者模式
1.1 观察者模式介绍
观察者(Observer)模式:
- 定义对象间的一种
一对多依赖关系
,使得每当一个对象状态发生改变
时,其相关依赖的对象皆得到通知
并被自动更新
;- 观察者模式又叫发布-订阅模式、模型-视图模式、源-监听器模式或从属者模式;
1.2 观察者模式结构
抽象主题(Subject)角色:
- 也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法;
具体主题(Concrete Subject)角色:
- 也叫具体目标类,它实现了抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过得观察者对象;
抽象观察者(Observer)角色:
- 它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用;
具体观察者(Concrete Observer)角色:
- 实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态;
二、实现
例子:
- 张三是个游戏主播,开播的时候通知订阅过他的人说,我开直播了,快来看我吧,粉丝得到通知到后可以进入对应的网站观看张三的直播;
2.1 观察者实现
package com.dozezz.designpattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
* 抽象主题
*/
public abstract class AbstractAnchorSubject {
/**
* 观察者的核心
*/
List<AbstractFansObserver> abstractFansObserverList = new ArrayList<>();;
/**
* 添加粉丝
*/
public abstract void addFans(AbstractFansObserver abstractFansObserver);
/**
* 通知粉丝
*/
public abstract void notifyFans(String msg);
}
package com.dozezz.designpattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
* 具体主题类
*/
public class ZhangSanSubject extends AbstractAnchorSubject{
public void startAnchor(){
System.out.println("张三,开始游戏直播。。");
notifyFans("我张大三开始王者荣耀游戏直播了,世界第一貂蝉,速来围观。。");
}
public void endAnchor(){
System.out.println("张三,结束游戏直播。。");
notifyFans("我张大三者荣耀游戏世界第一貂蝉直播结束了,可以看录播。。");
}
@Override
public void addFans(AbstractFansObserver abstractFansObserver) {
abstractFansObserverList.add(abstractFansObserver);
}
/**
* 观察者核心
* @param msg
*/
@Override
public void notifyFans(String msg) {
for (AbstractFansObserver fanObserver: abstractFansObserverList) {
fanObserver.accept(msg);
}
}
}
package com.dozezz.designpattern.observer;
/**
* 抽象观察者
*/
public abstract class AbstractFansObserver {
/**
* 粉丝接收推送信息方法
*/
public abstract void accept(String msg);
/**
* 粉丝关注主播
* @param abstractAnchorSubject
*/
void follow(AbstractAnchorSubject abstractAnchorSubject){
abstractAnchorSubject.addFans(this);
};
}
package com.dozezz.designpattern.observer;
/**
* 具体观察者
*/
public class LiSiObserver extends AbstractFansObserver{
@Override
public void accept(String msg) {
System.out.println(msg);
}
}
package com.dozezz.designpattern.observer;
/**
* 具体观察者
*/
public class RobotObserver extends AbstractFansObserver{
/**
* 为了增加观看直播的观众,主播花钱买的机器人
* @param msg
*/
@Override
public void accept(String msg) {
System.out.println("呸,老子是机器人,你发个毛毛。。。");
}
}
package com.dozezz.designpattern.observer;
/**
* 主測試類
*/
public class ClientTest {
public static void main(String[] args) {
ZhangSanSubject zhangsanSubject = new ZhangSanSubject();
new LiSiObserver().follow(zhangsanSubject);
new RobotObserver().follow(zhangsanSubject);
zhangsanSubject.startAnchor();
System.out.println("直播了八个小时。。。。");
zhangsanSubject.endAnchor();
}
}
2.2 双向观察
package com.dozezz.designpattern.observer;
/**
* 抽象观察者
*/
public abstract class AbstractFansObserver {
/**
* 双向观察
*/
// List<AbstractAnchorSubject> anchorSubjectList = new ArrayList<>();
/**
* 粉丝接收推送信息方法
*/
public abstract void accept(String msg);
/**
* 粉丝关注主播
* @param abstractAnchorSubject
*/
void follow(AbstractAnchorSubject abstractAnchorSubject){
abstractAnchorSubject.addFans(this);
};
}
package com.dozezz.designpattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
* 具体观察者
*/
public class LiSiObserver extends AbstractFansObserver{
@Override
public void accept(String msg) {
System.out.println(msg);
// for (AbstractAnchorSubject anchorSubject: anchorSubjectList) {
//
// }
}
}
三、观察者模式总结
3.1 观察者的应用场景
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象;
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,可将这两个封装为独立的对象中使他们可以各种独立地改变和复用;
- 实现类似广播机制的功能,不需要知道具体的接听者,只需要分发广播,系统中感兴趣的对象自动接收改广播;
- 多层及嵌套使用,形成一种链式触发机制,使得事件具备跨域通知;
3.2 观察者、中介者区别
观察者模式用于一对多依赖场景中解耦,通过引入Observer 角色,将消息发布者与具体的订阅者进行解耦;
中介者是将系统内部多对多的复杂耦合关系,借助于中介者进行解耦,将网状结构简化为星型结构,将多对多转换为一对多;
他们都能实现消息发布者与接受者的解耦,消息发布者都不知道具体的消息接收者;
两个模式之间是一种类似的关系,在有些场景可替代转换
- 如果协作关系比较简答,可以实现为一对多的形式,使用观察者模式;
- 如果协作关系更加复杂,那么就可以使用中介者模式;
3.3 观察者模式优缺点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,符合依赖倒置原则;
- 目标与观察者之间建立了一套触发机制;
目标鱼观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用;
当观察对象很多时,通知的发布回花费很多时间,影响程序的效率;
四、参考文献
- http://c.biancheng.net/view/1390.html
- https://www.cnblogs.com/noteless/p/10178477.html
- https://www.bilibili.com/video/BV1G4411c7N4?p=54&spm_id_from=pageDriver