观察者模式
观察者模式属于行为型模式
定义:
首先来了解一下观察者模式的定义:
观察者模式又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
角色组成:
观察者模式一共有四个角色:
Subject:抽象主题(抽象被观察者),可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
Observer:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知是更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update()方法,也就是更新方法。
ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。具体主题角色通常用一个具体子类实现。
ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
类图:
案例实现:
在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给
关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号
是被观察者,有多个的微信用户关注了 一个程序员的成长 这个公众号。
代码如下:
定义抽象观察者类,里面定义一个更新的方法
public interface Observer {
/**
* 更新方法
*
* @param message 通知信息
*/
void update(String message);
}
定义具体观察者类,微信用户是观察者,里面实现了更新的方法,这里用一个输出语句代替具体方法逻辑。
public class WeixinUser implements Observer {
// 微信用户名
private String nickName;
public WeixinUser(String nickName) {
this.nickName = nickName;
}
@Override
public void update(String message) {
System.out.println(nickName + " 收到通知 : " + message);
}
}
定义抽象主题类,提供了attach、detach、notify三个方法
public interface Subject {
/**
* 添加订阅者(添加观察者对象)
*
* @param observer 订阅者对象
*/
void attach(Observer observer);
/**
* 删除订阅者
*
* @param observer 订阅者对象
*/
void detach(Observer observer);
/**
* 通知订阅者更新消息
*
* @param message 更新消息
*/
void notify(String message);
}
微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法
public class SubscriptionSubject implements Subject {
/**
* 定义一个集合,用来存储多个观察者对象
*/
private List<Observer> weiXinUserList = new ArrayList<Observer>();
public void attach(Observer observer) {
weiXinUserList.add(observer);
}
public void detach(Observer observer) {
weiXinUserList.remove(observer);
}
public void notify(String message) {
//遍历集合
for (Observer observer : weiXinUserList) {
//调用观察者对象中的update方法
observer.update(message);
}
}
}
测试类
public class Test {
public static void main(String[] args) {
//1创建公众号对象
SubscriptionSubject subject = new SubscriptionSubject();
//2添加用户订阅公众号
subject.attach(new WeiXinUser("candou"));
subject.attach(new WeiXinUser("maiya"));
subject.attach(new WeiXinUser("bingfeng"));
//3公众号更新,发出消息给订阅者
subject.notify("一个程序员的成长 公众号更新了");
}
}
输出结果:
candou 收到通知 : 一个程序员的成长 公众号更新了
maiya 收到通知 : 一个程序员的成长 公众号更新了
bingfeng 收到通知 : 一个程序员的成长 公众号更新了
优缺点:
优点:
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,从而使得各自的变化都不会影响另一边的变化。
被观察者发送通知,所有注册的观察者都会收到信息【可以实现广播机制】
缺点:
如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知,尤其是涉及到数据库的操作时会比较耗时,
如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃
使用场景
当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,应考虑使用观察者模式。