sincerit 观察者模式(Observer Pattern)
目标(Subject)即观察者观察的对象
观察者(Observer)
观察者模式:主要特点是对象之间是一对多的依赖关系,每当目标(subject)的状态发生改变时,其相关的观察者(observer)做出相应的行为
观察者模式:由一个Subject抽象目标类,ConcreteSubject具体目标类,Observer抽象观察者,ConcreteObserver具体观察者组成
观察者模式:是23种设计模式之一,也是使用频率最高的设计模式之一,是一种行为型模式
观察者模式:实质是目标(Subject)类聚合(当成成员)一个观察者的列表(list),并且有增删的方法,以及一个notify()通知函数和一个状态量state,当状态量改变时目标(Subject)发送通知告诉观察者,观察者列表的观察者改变行为(obs.update())
观察者模式结构图:
图片来源: https://www.cnblogs.com/renhui/p/6479748.html
观察者模式有两种方法通知观察者状态发生改变:
- 推模式:通知观察者状态改变时,把状态传给观察者 obs.update(state),再根据何种状态做出相应行为;
- 拉模式:目标聚合观察者的同时,观察者也把观察目标对象(Subject)当成成员,当通知观察者状态改变时,观察者通过subject得到状态(getState()),再根据state做出相应行为
推模式和拉模式的区别结构图中就是ConcreteSubject和ConcreteObserver是否有联系(上图的是拉模式)
观察者模式所包含的类:
Subject:抽象目标类,把具体目标类抽象出来便于扩展其他具体目标类,该类包含一个观察者列表,对列表的处理方法(增删…),最重要的要有notify()通知方法
Observer:抽象观察者类,对具体观察者类做抽象,因为观察者有很多不同类型的观察者,把这些观察者共有的放放到抽象类,公共的有update()方法
ConcreteSubject:具体目标类,继承Subject,本身有一个状态量,状态改变就发送通知,通知观察者(至于观察者做出什么行为就管不着了,只是通知做出行为)
ConcreteObserver:具体观察者类,根据通知做出相应的行为 obs.update()
Client:客户端类,负责创建目标类及观察者类并调用通知函数
由于观察者模式的使用频率很频繁,JDK对观察者模式的支持,提供了Observerable类和Observer接口,Observerable相当于抽象目标类(Subject) ,Observer是抽象观察者。
JDK提供的Observerable类及Observer接口结构图
图片来源:https://www.cnblogs.com/renhui/p/6479748.html
考虑到推模式和拉模式,所以有update(Observerable o, Object arg)会传递一个目标做参数,并且考虑到通知的信息会很复杂,就封装成一个对象Object
软件公司欲开发一款多人联机对战游戏(类似魔兽世界、星际争霸等游戏),在该游戏中,多个玩家可以加入同一战队组成联盟,当战队中某一成员受到敌人攻击时将给所有其他盟友发送通知,盟友收到通知后将作出响应。
解决方案(结构图):
图片来源: https://www.cnblogs.com/renhui/p/6479748.html
实现代码:
抽象目标类
import java.util.ArrayList;
// 注意这里是自己实现Observer不可以到Observer的包
abstract class AllyControlCenter {
protected String allyName;
// 聚合一个Observer队列
protected ArrayList<Observer> players = new ArrayList<Observer>();
public void setAllyName(String name) {
this.allyName = name;
}
public String getAllyName() {
return allyName;
}
// 添加observer的方法
public void join(Observer obs) {
System.out.println(obs.getName() + "加入" + this.allyName + "战队");
players.add(obs);
}
// 删除observer的方法
public void quit(Observer obs) {
System.out.println(obs.getName() + "退出" + this.allyName + "战队");
players.remove(obs);
}
public abstract void notifyObserver(String name);
}
具体目标类
public class ConcreteAllyControlCenter extends AllyControlCenter {
public ConcreteAllyControlCenter(String name) {
System.out.println(name + "战队组建成功");
this.allyName = name;
}
// 具体目标类实现具体的通知方法
@Override
public void notifyObserver(String name) {
System.out.println(this.allyName+"紧急通知:" + name + "遭受敌人攻击");
for (Object obs : players) { // 集合是不会记住元素的类型的
if (!((Observer)obs).getName().equalsIgnoreCase(name)) {
((Observer)obs).help();
}
}
}
}
观察者抽象(接口)类
public interface Observer {
public String getName();
public void setName(String name);
public void help(); // 观察者救援别人的方法
public void beAttacked(AllyControlCenter acc); // 被攻击发送消息给目标类
}
具体观察者类
public class Player implements Observer {
private String name; // 观察者的名字
public Player(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
// 具体观察者实现救援方法
@Override
public void help() {
System.out.println(name + "前来救援");
}
// 观察者被攻击,通知战队控制中心,控制中心通知其他盟友来救援
@Override
public void beAttacked(AllyControlCenter acc) {
System.out.println(name+"被攻击");
acc.notifyObserver(name);
}
}
客户端类
public class Client {
public static void main(String[] args) {
AllyControlCenter acc;
acc = new ConcreteAllyControlCenter("金庸群侠");
Observer player1, player2, player3, player4;
player1 = new Player("杨过");
acc.join(player1);
player2 = new Player("令狐冲");
acc.join(player2);
player3 = new Player("张无忌");
acc.join(player3);
player4 = new Player("段誉");
acc.join(player4);
// 遭受攻击
player2.beAttacked(acc);
}
}
观察者类总结:
待续。。