对象间的联动----观察者模式(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,会有一定的感受和认识,欢迎留言交流。

 

 

 

 

 

更多推荐