前面两篇文章已经把父类和子类
关系型模式说完了。
今天开始介绍普通类之间构成的关系型设计模式。首先来说说观察者模式
。
还是这张概总图。
在现实世界中,许多对象都不是独立存在的。其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。
例如:
这样的例子还有很多……
这些情况下,如果用观察者模式来实现就非常方便。
观察者模式
是对象的行为模式。有的地方称作的发布-订阅模式
、模型-视图模式
、源-监听器模式
、从属者模式
等,当你看到这种叫法时,不要觉得陌生,它们都是观察者模式。
观察者模式
是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。
它可以实现对象之间的松耦合通信,当一个对象发生变化时通知其它相关的对象做出相应的响应。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
观察者模式
中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。
观察者模式的结构中包含四种角色:
(1)主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。
(2)观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。
(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。
(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。
我们现在来简单实现下公众号发送推文,大家就能接受消息的这一场景。
1、定义一个抽象被观察者接口--主题
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
2、定义一个抽象观察者接口 -- 观察者
public interface Observer {
public void update(String message);
}
3、定义具体的被观察主题 -- 具体主题
实现了 Subject 接口,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。
public class WechatServer implements Subject {
private List<Observer> list;
private String message;
public WechatServer() {
list = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
list.add(o);
}
@Override
public void removeObserver(Observer o) {
// TODO Auto-generated method stub
if (!list.isEmpty()) {
list.remove(o);
}
}
@Override
public void notifyObserver() {
// TODO Auto-generated method stub
for (Observer o : list) {
o.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("程序视点更新消息: " + s);
// 消息更新,通知所有观察者
notifyObserver();
}
}
4、定义具体观察者,微信公众号的具体观察者为用户User
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}
}
🆗,让我们来测试下
public class MainTest {
public static void main(String[] args) {
WechatServer server = new WechatServer();
Observer userZhang = new User("ZhangSan");
Observer userLi = new User("LiSi");
Observer userWang = new User("WangWu");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("【程序视点】为大家不定时推送消息!");
System.out.println("----------------------------------------------");
server.removeObserver(userZhang);
server.setInfomation("【程序视点】的读者是世界上最好的读者!");
}
}
输出:程序视点更新消息:【程序视点】为大家不定时推送消息! ZhangSan 收到推送消息:【程序视点】为大家不定时推送消息! LiSi 收到推送消息:【程序视点】为大家不定时推送消息! WangWu 收到推送消息:【程序视点】为大家不定时推送消息! ----------------------------------------------程序视点更新消息:程序视点】的读者是世界上最好的读者! ZhangSan 收到推送消息:程序视点】的读者是世界上最好的读者! LiSi 收到推送消息:程序视点】的读者是世界上最好的读者! WangWu 收到推送消息:程序视点】的读者是世界上最好的读者!
观察者模式理解起来比较简单。主要注意以下几点:
观察者模式的应用场景如下:
ps:当一个对象的行为改变时,需要改变其它的对象的行为的情况。
ps:一个事件发生,引起多个其他事件变化的情况。
ps:即当一个对象必须通知其他对象,但是却不能与其他对象造成紧密耦合的情况。
通过上面的分析,我们很容易发现观察者模式的优点:解除耦合。让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。
那有没有什么缺点呢?
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂。
在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率。在这种情况下,解决方法一般会采用异步实现。