【Java设计模式】之观察者模式
对象间的联动----观察者模式(Observer Pattern)
一、观察者模式概念
红灯停,绿灯行,在生活中,交通信号灯装点着我们的城市,指挥着日益拥挤的交通。当红灯亮起,来往的车辆都停止,当绿灯亮时,来往的车辆继续前行。在这个过程中,交通信号灯是观察目标,汽车是观察者,随着交通信号灯的变化,汽车根据反应作出不同的行为。一盏交通信号灯可以同时指挥很多辆汽车。如下图,信号灯的变化,可以引起汽车行为的变化。
在软件系统中,也存在类似交通灯和汽车之间的这种关系,一个对象的状态或者行为的变化,将导致其他对象状态或者行为也发生改变,正所谓’牵一发而动全身‘。 为了更好的描述对象之间的这种一对多(也包括一对一)联动的关系,观察者模式应运而生。它定义了一种一对多的依赖关系,让一个对象的改变可以影响其他对象。
二、观察者模式设计思路
观察者模式结构中通常包括观察目标和观察者两个继承层次结构,其图如下。

- Subject:就是观察目标,它将所有观察者对象的引用保存在一个集合中,是抽象类,需要一个实现类。
- Observer:是抽象的“观察者”,是一个接口,它定义了一个更新方法,使得在观察目标状态发生改变时通知自己。
- ConcreteObserver:具体的观察者,实现了Observer接口。
三、观察者模式实现案例
这里通过一个小游戏来实现观察者模式:现在有一款多人联机对战的游戏(类似英雄联盟),在该游戏中,多个玩家可以加入一个战队,组成联盟。当战队中某个玩家收到攻击之后,将给所有的其他盟友发送消息,盟友收到通知之后会收到回应。
玩家是多的一方,也就是观察者,那么一的一方,也就是观察目标在哪里呢?
我们可以引入一个作战中心,作为指挥调度的观察目标,对象联动关系就成了如下:
某个盟军受到攻击--->发送消息给作战中心--->作战中心统一通知所有其他盟军
代码实现如下:
1、观察目标(作战中心)
package com.bayss.designmodule.obServerPattern;
import java.util.ArrayList;
import java.util.List;
/**
* @author fengjiale
* @create 2019-09-02 15:54
* @desc 观察目标类
**/
public abstract class AllyControlCenter {
protected String allyName; //战队名称
//定义一个观察者集合
protected List<ObServer> players = new ArrayList<>();
public void setAllyName(String allyName){
this.allyName = allyName;
}
public String getAllyName(){
return this.allyName;
}
//注册加入战队方法
public void join(ObServer obServer){
System.out.println(obServer.getName()+"加入"+this.allyName);
players.add(obServer);
}
//注销退出战队方法
public void quit(ObServer obServer){
System.out.println(obServer.getName()+"退出"+this.allyName);
players.remove(obServer);
}
//声明抽象通知方法
public abstract void callObServer(String name);
}
class ConCreAllyControlCenter extends AllyControlCenter{
public ConCreAllyControlCenter(String allyName){
System.out.println(allyName+"战队创建成功");
System.out.println("-----------------");
this.allyName = allyName;
}
//通知观察者们
@Override
public void callObServer(String name) {
System.out.println(this.allyName+"战队紧急通知:"+name+"正在遭受攻击");
for(ObServer obServer : players){
if(!name.equals(obServer.getName())){
obServer.help();
}
}
}
}
抽象作战中心维护了一个玩家的集合,并且提供了加入战队和退出战队的方法。实现的作战中心通过构造方法可以定义战队的名字,创建战队,实现了具体的通知玩家们的方法callObServer。
2、观察者(玩家们)
package com.bayss.designmodule.obServerPattern;
/**
* @author fengjiale
* @date 2019-09-02 17:00
* @param
* @desc
*/
public interface ObServer {
public String getName();
public void setName(String name);
public void help(); //声明支援盟友的方法
public void beAttacked(AllyControlCenter acc); //声明收到攻击的方法
}
class Player implements ObServer{
private String name;
public Player(String name){
this.name = name;
}
@Override
public String getName() {
return this.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.callObServer(name);
}
}
观察者接口中定义了help()支援盟友的方法,和遭受攻击的方法。Player类实现了ObServer类,实现了这两个方法,可以看到,遭受攻击的方法中,调用了通知作战中心的方法,作战中心将收到通知,并且调用通知盟军的方法。
3、测试方法
package com.bayss.designmodule.obServerPattern;
/**
* @author fengjiale
* @create 2019-09-02 16:23
* @desc 测试程序
**/
public class Test {
public static void main(String[] args) {
AllyControlCenter acc = new ConCreAllyControlCenter("神奇四侠");
//定义四个观察者,分别加入战队
ObServer ob1 = new Player("钢铁侠");
acc.join(ob1);
ObServer ob2 = new Player("蜘蛛侠");
acc.join(ob2);
ObServer ob3 = new Player("熊猫侠");
acc.join(ob3);
ObServer ob4 = new Player("煎饼侠");
acc.join(ob4);
ob1.beAttacked(acc);
}
}
4、查看日志
神奇四侠战队创建成功
-----------------
钢铁侠加入神奇四侠
蜘蛛侠加入神奇四侠
熊猫侠加入神奇四侠
煎饼侠加入神奇四侠
我是钢铁侠,我正在遭受攻击!
神奇四侠战队紧急通知:钢铁侠正在遭受攻击
坚持住,我是蜘蛛侠,我来救你了!
坚持住,我是熊猫侠,我来救你了!
坚持住,我是煎饼侠,我来救你了!
相信大家看了,动手做了这个Demo,会有一定的感受和认识,欢迎留言交流。
更多推荐



所有评论(0)