定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。也就是就是当一个行为发生时传递信息给另外一个用户接收做出相应的处理,但是两者之间没有直接的耦合关联。
观察者模式一般分为4类:
- 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
=========================================================================
我们实现一个例子:
我们在商店设置一个自动推送,当显卡补货了我们就给关注商店的人推送补货信息,卖出推送卖出信息,如果不关注了就不推送信息了。
首先我们创建一个抽象观测者的接口:
package ObserverPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Observer.java
* @Description 抽象观测者接口
* @createTime 2022年03月10日 16:17:00
*/
public interface Observer {
/**
* 更新信息
* @param message 传过来的信息
*/
public void update(String message);
}
我们观测到了被观测者有情况,就调用发送信息的方法。
然后创建一个具体的观测者的类,也就是我们需要发送信息的主体,订阅的用户:
package ObserverPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName User.java
* @Description 具体的观测者,用户:接受信息
* @createTime 2022年03月10日 16:18:00
*/
public class User implements Observer{
private String name;
public User(String name) {
this.name = name;
}
/**
* 发送消息
* @param message 传过来的信息
*/
@Override
public void update(String message) {
System.out.println(name +" 收到信息:"+ message);
}
}
创建抽象被观察者角色:
package ObserverPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Subject.java
* @Description 抽象被观察者接口
* @createTime 2022年03月10日 16:05:00
*/
public interface Subject {
/**
* 订阅频道
* @param observer 用户
*/
public void subscribe(Observer observer);
/**
* 取消订阅
* @param observer 用户
*/
public void unSubscribe(Observer observer);
/**
* 通知观测者
* @param message 消息
*/
public void notifyObserver(String message);
}
实现观察者的增减,以及推送信息。
具体被观察者角色:
package ObserverPattern;
import java.util.ArrayList;
import java.util.List;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName User.java
* @Description 消息中心
* @createTime 2022年03月10日 16:15:00
*/
public class OrderCenter implements Subject {
private List<Observer> list;
private String message;
public OrderCenter(){
list = new ArrayList<Observer>();
}
/**
* 订阅
* @param observer 用户
*/
@Override
public void subscribe(Observer observer) {
list.add(observer);
System.out.println("订阅成功");
}
/**
* 取消订阅
* @param observer 用户
*/
@Override
public void unSubscribe(Observer observer) {
if(list.remove(observer)) {
System.out.println("取消订阅成功");
}else {
System.out.println("取消订阅失败");
}
}
/**
* 发送信息
*/
@Override
public void notifyObserver(String message) {
System.out.println("开始发送信息:");
for (Observer observer: list) {
observer.update(message);
}
}
/**
* 设置发送的信息
* @param message 息
*/
public void setInformation(String message) {
this.message = message;
// 消息更新,通知所有观察者
notifyObserver(message);
}
}
我们把具体被观察者定义为一个订阅中心,内部状态改变时,所有登记过的观察者发出通知。
我们定义一个商店接口,被被观察者监控:
package ObserverPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Shop.java
* @Description 商店接口
* @createTime 2022年03月10日 16:33:00
*/
public interface Shop {
/**
* 进货
* @param subject 被观察者接口
* @param order 增加的显卡数量
*/
public void addCards(Subject subject,int order);
/**
* 出售
* @param subject 被观察者接口
* @param order 出售的显卡数量
*/
public void saleCards(Subject subject,int order);
}
实现商店为一个具体的显卡商店:
package ObserverPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName GraphicShop.java
* @Description 显卡商店
* @createTime 2022年03月10日 16:34:00
*/
public class GraphicShop implements Shop{
private int repertory;
public GraphicShop(int repertory){
this.repertory = repertory;
}
/**
* 显卡补货
* @param subject 被观察者接口
* @param order 增加的显卡数量
*/
@Override
public void addCards(Subject subject,int order) {
repertory+=order;
subject.notifyObserver("显卡补货了"+order+"张");
}
/**
* 卖卡
* @param subject 被观察者接口
* @param order 出售的显卡数量
*/
@Override
public void saleCards(Subject subject,int order) {
if (repertory>0){
if (order>repertory){
int sale = order-repertory;
repertory = 0;
subject.notifyObserver("显卡不足,售出"+sale+"张");
}else {
repertory -= order;
subject.notifyObserver("出售了" + order + "张");
}
}else {
subject.notifyObserver("显卡售空了");
}
}
}
每当我的显卡商店有任何的动作,我的被观测者就会被调用,与此同时观测者就会收到商店变化的消息。
测试一下:
package ObserverPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName ObserverTest.java
* @Description 测试
* @createTime 2022年03月10日 16:42:00
*/
public class ObserverTest {
public static void main(String[] args) {
//创建用户
User user1 = new User("张三");
User user2 = new User("李四");
User user3 = new User("王五");
//创建消息中心
Subject subject = new OrderCenter();
//用户订阅消息
subject.subscribe(user1);
subject.subscribe(user2);
subject.subscribe(user3);
//商店库存
int repository = 50;
//创建显卡商店
Shop graphicShop = new GraphicShop(repository);
//商店进货与卖卡
graphicShop.addCards(subject,300);
graphicShop.saleCards(subject,200);
//取消关注
subject.unSubscribe(user2);
graphicShop.saleCards(subject,200);
graphicShop.saleCards(subject,200);
}
}
优点:
- 1、观察者和被观察者是抽象耦合的。
- 2、建立一套触发机制。
缺点:
- 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。