观察者模式
定义对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时其相关依赖对象皆得到通知并被自动更新,是一种对象行为型模式
类图
实现
Subject(目标):指被观察的对象,可以接受任意数量的观察者来观察,定义了通知方法
package design.observer.realize;
import java.util.ArrayList;
/*
*
*@author:zzf
*@time:2020-12-20
*
*/
public abstract class Subject {
//定义了一个观察者集合用于存储所有观察者对象
protected ArrayList<Observer> observers=new ArrayList();
//注册方法,用于向观察者集合中增加一个观察者
public void attach(Observer observer){
observers.add(observer);
}
//注销方法,用于从观察者集合中删除一个观察者
public void detach(Observer observer){
observers.remove(observer);
}
//声明抽象通知方法
public abstract void notify();
}
ConcreteSubject(具体目标)
package design.observer.realize;
/*
*
*@author:zzf
*@time:2020-12-20
*
*/
public class ConcreteSubject extends Subject {
@Override
public void notify() {
//遍历观察者集合,调用每一个观察者的响应方法
for (Object obs:observers) {
((Observer)obs).update();
}
}
}
Observer,抽象观察者,一般定义为接口
package design.observer.realize;
/*
*
*@author:zzf
*@time:2020-12-20
*
*/
public interface Observer {
//声明响应方法
public void update();
}
具体观察者
package design.observer.realize;
/*
*
*@author:zzf
*@time:2020-12-20
*
*/
public class ConcreteObserver implements Observer {
//实现响应方法
public void update(){
//具体响应代码
}
}
客户端
package design.observer.realize;
/*
*
*@author:zzf
*@time:2020-12-20
*
*/
public class Client {
public static void main(String[] args) {
Subject subject=new ConcreteSubject();
Observer observer=new ConcreteObserver();
subject.attach(observer);
subject.notify();
}
}
应用实例
在某多人联机对战游戏中,多个玩家可以加入同一战队组成联盟,当战队中的某一成员受到敌人攻击时将给所有其他盟友发送通知,盟友收到通知后将做出响应。
现使用观察者模式设计并实现该过程,以实现战队成员之间的联动。
代码实现
抽象目标类,指挥部
package design.observer;
import java.util.ArrayList;
import java.util.List;
/**
*
* 抽象目标类
*
*/
public abstract class AllyControlCenter {
protected String allyName;// 战队名称
// 定义一个集合用于存储战队队员
protected List<IObserver> players = new ArrayList<IObserver>();
public String getAllyName() {
return allyName;
}
public void setAllyName(String allyName) {
this.allyName = allyName;
}
// 注册方法
public void join(IObserver obs) {
System.out.println(obs.getName() + "加入" + this.allyName + "战队!");
players.add(obs);
}
// 注销方法
public void quit(IObserver obs) {
System.out.println(obs.getName() + "退出" + this.allyName + "战队!");
players.remove(obs);
}
// 抽象通知方法
public abstract void notifyObserver(String name);
}
具体目标类,具体指挥部
package design.observer;
/**
*
* 具体目标类
*
*/
public class ConcreteAllyControlCenter extends AllyControlCenter {
public ConcreteAllyControlCenter(String allyName) {
System.out.println(allyName + "战队组建成功!");
System.out.println("---------------------");
this.allyName = allyName;
}
@Override
public void notifyObserver(String name) {
System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击!");
// 遍历观察者集合,调用每一个盟友的支援方法
for (Object obs : players) {
if (!((IObserver) obs).getName().equals(name)) {
((IObserver) obs).help();
}
}
}
}
抽象观察者类
package design.observer;
/**
*
* 抽象观察者类
*
*/
public abstract class IObserver {
protected String name;
public abstract void help();// 支援盟友方法
public abstract void beAttacked(AllyControlCenter acc);// 遭受攻击方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
具体观察者类
package design.observer;
/**
*
* 战队成员类,充当具体观察者类
*
*/
public class Player extends IObserver {
public Player(String name) {
this.name = name;
}
@Override
public void help() {
System.out.println("坚持住," + this.name + "来救你!");
}
@Override
public void beAttacked(AllyControlCenter acc) {
System.out.println(this.name + "被攻击!");
acc.notifyObserver(name);
}
}
客户端
package design.observer;
public class Client {
public static void main(String[] args) {
// 定义观察目标对象
AllyControlCenter acc;
acc = new ConcreteAllyControlCenter("金庸群侠");
// 定义四个观察者对象
IObserver 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);
player1.beAttacked(acc);
}
}
运行效果
观察者模式的优缺点
优点:
(1)可以实现表示层和数据逻辑层的分离
(2)在观察目标和观察者之间建立一个抽象的耦合
(3)支持广播通信且符合开闭原则
缺点:
(1)将所有的观察者都通知到会花费很多时间
(2)如果存在循环调用可能导致系统崩溃
(3)没有响应的机制让观察者知道所观察的目标对象是怎样发生变化的,而仅知道观察目标发生了变化
适用环境
(1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用
(2)一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁
(3)需要在系统中创建一个触发链
参考
Java设计模式