观察者模式
在软件系统中,各个对象并不是孤立存在的,经常会出现一个对象的状态发生了变化,会导致其他一个或者多个存在依赖关系的对象跟随变化的场景。观察者模式用来描述对象之间的依赖关系,为实现多个对象之间的联动提供了一种解决方案。
定义
观察者模式定义了一种一对多的依赖关系,每当一个对象的状态发生变化的时候,其他依赖对象都会得到通知并发生相应变化。
结构
观察者模式通常包含观察者和观察目标两个部分。
- Subject(观察目标):它是被观察的对象,内部定义了一个观察者集合以及添加观察者、删除观察者、通知观察者的方法
- ConcreteSubject(具体观察目标):观察目标的继承类或者实现类。内部定义了某个经常发生变化的状态以及状态的改变方法,状态改变后,会调用相应的通知观察者的方法
- Observer(观察者):观察者将对观察目标的状态改变做出反应,内部声明了update方法,一般被定义为接口,由实现类定义具体的update方法
- ConcreteObserver(具体观察者):观察者的实现类,定义了具体的update方法,当观察目标的状态发生变化的时候被执行
实例
设计一个简单的游戏开始功能。游戏倒计时,当倒计时到0时,战队成员接到通知出发。当游戏时间到0时,战队成员接到通知停止游戏。
package observer;
import java.util.ArrayList;
import java.util.List;
public abstract class BattleTeam {
private List<Member> memberList = new ArrayList<>();
public void addMember(Member member) {
this.memberList.add(member);
}
public void removeMember(Member member) {
this.memberList.remove(member);
}
public void changeState(boolean startStatus) {
memberList.forEach(m->m.executeCommand(startStatus));
}
}
package observer;
public class ConcreteBattleTeam extends BattleTeam{
private boolean startStatus = false;
public void start() {
this.startStatus = true;
this.changeState(startStatus);
}
public void end() {
this.startStatus = false;
this.changeState(startStatus);
}
}
package observer;
public interface Member {
void executeCommand(boolean startStatus);
}
package observer;
public class ConcreteMember implements Member{
private String name;
public ConcreteMember(String name) {
super();
this.name = name;
}
@Override
public void executeCommand(boolean startStatus) {
if (startStatus) {
System.out.println(name + "出发");
} else {
System.out.println(name + "停止");
}
}
}
package observer;
public class Test {
public static void main(String[] args) throws InterruptedException {
BattleTeam team = new ConcreteBattleTeam();
Member zhangsan = new ConcreteMember("张三");
Member lisi = new ConcreteMember("李四");
Member wangwu = new ConcreteMember("王五");
Member zhaoliu = new ConcreteMember("赵六");
team.addMember(zhangsan);
team.addMember(lisi);
team.addMember(wangwu);
team.addMember(zhaoliu);
for (int i = 5; i > 0; i--) {
System.out.println("距离开始" + i + "秒");
Thread.sleep(1000);
}
team.changeState(true);
Thread.sleep(2000);
team.changeState(false);
}
}
优点
- 实现了数据表示层和数据逻辑层的分离,使得功能进行解耦
- 在观察目标和观察者之间建立一个抽象的耦合,观察目标不需要具体了解观察者
- 支持广播通信,观察目标像所有注册的观察者进行通知,简化了一对多的设计难度
- 符合开闭原则,增加新的观察者的时候不需要堆观察目标进行改动
缺点
- 观察目标和观察者之间尽量不能存在相互调用,不然可能触发循环导致系统崩溃
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,只知道变化的结果
使用场景
- 一个抽象模型有两个方面,一个方面依赖于另一个方面的变化,可以将两个方面拆分,使其独立发展
- 一个对象的改变会导致一个或者多个对象也发生相应的变化,而且这些对象个数可能动态改变