这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战
欢迎来到今天的学习,今天我们一起来学习下使用频率很高且实践比较多的一种模式----观察者模式。多唠叨几句,我本月将会对java的设计模式精讲,欢迎点击头像,关注我的专栏,我会持续更新,加油!
系列文章:
...持续更新中
话不多说,进入正题
观察者模式
观察者模式是一种非常流行的设计模式,也有人称之为订阅-发布模式,我个人认为都是一种思想,就是一对象当中,任何的改变,都能被监听到,识别到,然后去通知改变,这个行为也可以称之为“事件”,观察者通过处理每一个事件来完成自身的操作处理
观察者模式的原始定义是:定义对象之间的一对多依赖关系,这样当一个对象改变状态时,它的所有依赖项都会自动得到通知和更新。
注意:该定义当中,对象之间的是一对多,那么这个一就是观察者,只有一个观察者在观察动态,多便是指被观察者。我们还可以称观察者模式为以下几种叫法,不过不管怎么叫,本质都是观察者模式的思想
-
事件发布,事件监听
-
发布者-订阅者
-
生产者-消费者
这种模式在各种框架源码当中也屡见不鲜,很适合在实践中运用与巧妙处理。
我以前写过一篇干货实战文章,就是利用Spring当中的监听来完成的,有兴趣的可以看下:
回归正题,下面看下,观察者模式的图(图片来源于网路)
从上图中,我们能看出观察者模式包含的四个关键角色:
1 、发布者(Publisher),也被叫作主题、被订阅者、被观察者等
2、 具体发布者(PublisherImpl),实现了发布者定义的方法的具体实现类
3、订阅者(Observer):也叫作观察者,它会存储一个注册列表,用于存放订阅者。当发布者发布消息或事件时,会通知到订阅者进行处理。
4、 具体订阅者(ObserverImpl):实现具体定义的方法操作。
接下来我们通过一个场景和代码来让你深入理解下:
场景分析及代码展示
使用场景分析:
我们拿微信公众号推文场景来展示下,我们都知道我们的公众号推文文章只会推送给关注我公众号的人,那么,假如我今天发表一篇名为“java观察者模式”一篇推文,张三,李四,王五关注了我的公众号,那么我点击发布,就会往他们的微信上推。
我们首先定义观察者 ArticleObserver。它只有一个 send 方法,当有文章 Article 发送过来时就会调用该方法。
public interface ArticleObserver {
void send(Articl m);
}
接着再定义文章的具体数据结构,这里使用一个 content 文章内容。
public class Articl {
final String content;
public Articl (String m) {
this.content = m;
}
public String getContent() {
return content;
}
}
然后,再来定义一个被观察者 Subject ,它定义了三个方法:增加观察者方法 attach、删除观察者方。
public interface Subject {
void attach(ArticleObserver a); //增加观察者
void detach(ArticleObserver a); //删除观察者
void notifySend(Article m); //异步发送推文
}
再接下来,实现 Subject 的具体发布者类 ArticlePublisher,它持有一组观察者 ArticleObserver 实例,可以通过 attach 和 detach 接口方法新增和删除观察者,异步通知发送方法 notifySend
public class ArticlePublisher implements Subject {
private List<ArticleObserver> observers = new ArrayList<>();
@Override
public void attach(ArticleObserver o) {
observers.add(o);
}
@Override
public void detach(ArticleObserver o) {
observers.remove(o);
}
@Override
public void notifySend(Articl m) {
observers.forEach(x->x.sed(m));
}
}
最后,我们实现三个具体订阅者类(张三,李四,王五),它们都实现(关注了该公众号)了 ArticleObserver 接口,分别要发送到三者微信当中。
//张三订阅
public class ZhangSanSubscriber implements ArticleObserver {
@Override
public void send(Articl a) {
System.out.println("ZhangSanSubscriber 看到 :: " + a.getContent());
}
}
//李四订阅
public class LisiSubscriber implements ArticleObserver {
@Override
public void send(Articl a) {
System.out.println("LisiSubscriber 看到 :: " + a.getContent());
}
}
//王五订阅
public class WangwuSubscriber implements ArticleObserver {
@Override
public void send(Articl a) {
System.out.println("WangwuSubscriber 看到 :: " + a.getContent());
}
}
单元测试下:
public class Client {
public static void main(String[] args) {
ArticleObserver zhangSan = new ZhangSanSubscriber();
ArticleObserver liSi = new LisiSubscriber();
ArticleObserver wangWu = new WangwuSubscriber();
Subject p = new ArticlePublisher();
// 增加订阅,将相应订阅者添加进去(集合)
p.attach(zhangSan);
p.attach(liSi);
p.attach(wangWu);
//发送推文
p.notifySend(new Articl("java观察者模式"));
}
}
//输出结果
ZhangSanSubscriber 看到 :: java观察者模式
LisiSubscriber 看到 :: java观察者模式
WangwuSubscriber 看到 :: java观察者模式
注意,我这里只是用了一篇文章(发布对象),可以多种。
OK,代码到这里就结束了。
上面的代码实现非常简单,但是充分体现了观察者模式的使用场景。观察者模式使用场景的特点在于找到合适的被观察者,定义一个通知列表,将需要通知的对象放到这个通知列表中,当被观察者需要发起通知时,就会通知这个列表中的所有“人”。
总结
使用观察者模式的优点:
-
由利用代码扩展性的提升,由于观察者和被观察之间是抽象耦合,所以扩展性较强
-
降低系统与系统之间的耦合性,比如,建立订阅者集合,可以随时添加或者删除该集合当中的某一元素。
有褒有贬:
我个人理解,会降低性能,观察者模式通常需要事件触发,当观察者对象越多时,被观察者需要通知观察者所花费的时间也会越长,这样会在某种程度上影响程序的效率。
看到这里可能会有伙伴问了,为什么使用观察者模式?,我认为有以下两点:
1、为了方便捕获观察对象的变化并及时做出相应的操作,比如快递的状态要及时变更等。
2、上面也说到了,为了提高代码的扩展性
弦外之音
感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。
我已经将本章收录在专题里,点击下方专题,关注专栏,我会每天发表干货,本月我会持续输入设计模式。
加油! 我们下期再见!