设计模式之二——从江湖情报变动通知各门派看观察者模式

我们看武侠小说的时候,有这么一个情节,就是武侠世界中总有一个神秘组织,对江湖的情报进行搜集,然后把情报进行分析整理,向江湖主要门派进行通报。将问题用更精确点的语言描述一遍,就是有一个情报组织,他们组织里有一些人在监视江湖上的各种事件,然后汇总到情报组织中,情报组织将所有情报进行汇总分析,有大的事件发生的时候他们把情报进行更新,更新的信息包括BigEvent武林大事件、WugongRank武功排行榜、WeaponRank武器排行榜等,然后将信息发放到Shaolin少林、Wudang武当、Emei峨眉等一些大门派。

设计模式之二——从江湖情报变动通知各门派看观察者模式

2 问题分析

这个业务关系和报纸出版的方式很类似,就是主办者+订阅者的方式,情报组织负责提供数据,各大门派开始订阅,如果信息变动则给订阅的门派提供信息,门派可以看作是观察者,可以注册,接收情报信息,也可以注销,不再接收信息。

情报数据和门派之间存在一对多的依赖,当情报数据发生改变时,所有的门派都会收到通知并自动更新数据。再用更通用的语言描述一次,定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。我们将情报数据抽象为subject主题,将各门派抽象为observer观察者,得到观察者模式的类图。

设计模式之二——从江湖情报变动通知各门派看观察者模式

主题和观察者相对独立,它们之间并不会相互影响,只要遵循接口关系设计,它们就可以被*的改变。这也是一个软件设计原则,尽量减少对象之间的耦合。松耦合的设计之所以能让我们建立有弹性的软件系统,就是因为松耦合能够应对变化,对象之间的依赖关系被降低了。

3 设计情报通知系统

根据观察者模式类图,我们进行江湖情报通知的详细设计,其中情报数据类实现主题接口,除了有注册观察者,移除观察者,通知观察者等方法外,还有获取情报的方法以及情报改变的方法,情报改变的方法用于在情报改变的时候,更新情报信息,然后执行通知观察者方法。

增加InformationDisplay信息展示接口,接口只提供一个display展示方法,用来展示各种数据。观察者的具体实现类既实现观察者接口,也实现信息展示接口。

设计模式之二——从江湖情报变动通知各门派看观察者模式

4 代码实现

根据上面的设计图,进行代码编程实现。

4.1 三个接口代码

public interface Subject {
   
public void registerObserver(Observer o);
    public void
removeObserver(Observer o);
    public void
notifyObserver();
}

public interface Observer {

    public void update(String bigEvent,String wugongRank,String weaponRank);

}
public interface InformationDisplay {

    public void display();

}

 

4.2 具体主题的实现类(情报数据类)

public class InformationData implements Subject {

    private ArrayList observers;//用来记录观察者

    private String bigEvent;

    private String wugongRank;

    private String weaponRank;



    public InformationData(){

        observers = new ArrayList();

    }



    public void registerObserver(Observer o){

        observers.add(o);

    }



    public void removeObserver(Observer o){

        int i = observers.indexOf(o);

        if (i >= 0){

            observers.remove(o);

        }

    }



    public void notifyObserver(){

        for (int i = 0;i < observers.size();i++){

            Observer observer = (Observer) observers.get(i);

            observer.update(bigEvent,wugongRank,weaponRank);

        }

    }



    public void informationChanged(){

        notifyObserver();

    }



    public void setInformation(String bigEvent,String wugongRank,String weaponRank){

        this.bigEvent = bigEvent;

        this.wugongRank = wugongRank;

        this.weaponRank = weaponRank;

        informationChanged();

    }

}

 

4.3 具体观察者实现类(武林大事件展示类)

具体观察者实现类有三个,武林大事件展示类、武功排名展示类和武器排名展示类,三个类比较相似,此处只以武林大事件展示类为例,进行代码展示。

public class BigEventDisplay implements Observer,InformationDisplay {



    private String bigEvent;

    private Subject informationData;



    public BigEventDisplay(Subject informationData){

        this.informationData = informationData;

        informationData.registerObserver(this);

    }



    @Override

    public void update(String bigEvent, String wugongRank, String weaponRank) {

        this.bigEvent = bigEvent;

        display();

    }



    @Override

    public void display() {

        System.out.println("当前发生的武林大事有:"+bigEvent);

    }

}

 

4.4 测试类及结果

public class InformationNotify {

    public static void main(String[] args) {

        InformationData informationData = new InformationData();



        BigEventDisplay bigEventDisplay = new BigEventDisplay(informationData);



        informationData.setInformation("五大派正在围攻光明顶,张无忌力战各大掌门。","张无忌排名第一","小李飞刀排名第一");

    }

}

"C:\Program Files\Java\jdk1.8.0_111\bin\java.exe" -

当前发生的武林大事有:五大派正在围攻光明顶,张无忌力战各大掌门。

Process finished with exit code 0

5 结语

观察者模式在JDK中也有实现,Java API内置的观察者模式,在java.util包内,其中Observable类对应我们的Subject接口,Observer接口对应我们的Observer接口,观察者模式的思想是一致的,使用上也比较类似,不过,JDK为我们做好的封装,使用起来更加方便。