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

我们看武侠小说的时候,有这么一个情节,就是武侠世界中总有一个神秘组织,对江湖的情报进行搜集,然后把情报进行分析整理,向江湖主要门派进行通报。将问题用更精确点的语言描述一遍,就是有一个情报组织,他们组织里有一些人在监视江湖上的各种事件,然后汇总到情报组织中,情报组织将所有情报进行汇总分析,有大的事件发生的时候他们把情报进行更新,更新的信息包括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 FilesJavajdk1.8.0_111injava.exe" -

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

Process finished with exit code 0

5 结语

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

原文地址:https://www.cnblogs.com/coodream2009/p/10657919.html