戏说模式之:观察者模式(三体)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了戏说模式之:观察者模式(三体)相关的知识,希望对你有一定的参考价值。

定义

观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)
是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。
这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

观察者模式结构

摘抄于Head First设计模式

该设计方式充分展现了松耦合的威力,当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者直接松耦合。

关于观察者的一切主题只知道观察者实现了某个接口(IObserver接口)。主题不需要知道具体的观察者是谁,内部实现了那些细节。

任何时候我们都可以添加新的观察者。因为主题唯一依赖的是一个实现IObserver接口的列表,所以我们可以随时添加或删除观察者,主题并不受任何影响。当有新的观察者出现的时候,主题的代码不需要做任何更改。只需要新的观察者实现IObserver接口即可
技术分享图片

理解

我们先引入一个场景,《三体》中三体星人向地球发送了一颗质子来监视和锁定地球,同时派遣三体舰队前来占领地球。质子把地球的情况时时发送给三体星三体舰队。在这里地球是信息载体,三体星三体舰队就是具体的观察者,质子则是地球信息收集和分发着。质子可以自行决定是否分发信息到三体星或三体舰队。
技术分享图片

《三体》场景的结构图

该结构图中定义了主题接口(ISubject),主题的实现接口(ConcreteSubject),观察者接口(IObserver),三体星观察者(ThreeBodyPlanet),三体舰队观察者(ThreeBodyFleet),地球资源bean(Earth),具体调用客户端质子(Proton)
技术分享图片

具体实现

主题接口
/**
 * 主题,每个观察者的管理接口
 */
public interface ISubject {
    public void addObserver(IObserver observer);
    public void deleteObserver(IObserver observer);
    public void notifyObserver(Earth earth);
}
主题具体实现
/**
 * 主题的具体实现类
 */
public class ConcreteSubject implements ISubject {
    List<IObserver> observers ;

    public ConcreteSubject(){
        this.observers = new ArrayList<IObserver>();
    }
    @Override
    public void addObserver(IObserver observer) {
        this.observers.add(observer);
    }

    @Override
    public void deleteObserver(IObserver observer) {
        this.observers.remove(observer);
    }

    @Override
    public void notifyObserver(Earth earth) {
        for(IObserver observer : observers){
            observer.update(earth);
        }
    }

    public void timeUp(Earth earth){
        this.notifyObserver(earth);
    }
}
观察者接口
/**
 * 观察者接口,只有一个update方法
 */
public interface IObserver {
    public void update(Earth earth);
}
地球资源实体
/**
 * 地球实体bean
 */
public class Earth {
    //武器
    private String weapon;
    //人口
    private long population;
    //技术
    private String technology;
    //水含量
    private float water;
    //温度
    private float temperature;
    //陆地
    private float land;

    public String getWeapon() {
        return weapon;
    }

    public void setWeapon(String weapon) {
        this.weapon = weapon;
    }

    public long getPopulation() {
        return population;
    }

    public void setPopulation(long population) {
        this.population = population;
    }

    public String getTechnology() {
        return technology;
    }

    public void setTechnology(String technology) {
        this.technology = technology;
    }

    public float getWater() {
        return water;
    }

    public void setWater(float water) {
        this.water = water;
    }

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }

    public float getLand() {
        return land;
    }

    public void setLand(float land) {
        this.land = land;
    }
}
三体星(观察者)
/**
 * 三体星球观察者
 */
public class ThreeBodyPlanet implements IObserver {
    @Override
    public void update(Earth earth) {
        System.out.println("======三体星球观察者====");
        StringBuffer buf = new StringBuffer();
        buf.append("水资源:"+earth.getWater()+"亿立方千米,");
        buf.append("温度:"+earth.getTemperature() + "℃,");
        buf.append("陆地:"+earth.getLand() + "亿平方公里,");
        buf.append("人口:"+earth.getPopulation() + "亿");
        System.out.println(buf.toString());
    }
}
三体舰队(观察者)
/**
 * 三体舰队观察者
 */
public class ThreeBodyFleet implements IObserver{
    @Override
    public void update(Earth earth) {
        System.out.println("======三体舰队观察者====");
        StringBuffer buf = new StringBuffer();
        buf.append("武器:"+earth.getWeapon()+",");
        buf.append("科技:"+earth.getTechnology() + ",");
        buf.append("人口:"+earth.getPopulation() + "亿");
        System.out.println(buf.toString());
    }
}
质子(信息收集发布)
/**
 * 向三体汇报地球情况的质子
 */
public class Proton {
    @Test
    public void report(){
        Earth earth = new Earth();

        earth.setLand(5.11f);
        earth.setPopulation(70);
        earth.setTechnology("能够利用核能,未掌握曲率引擎,无星际旅行能力");
        earth.setTemperature(15.8f);

        earth.setWater(14f);
        earth.setWeapon("最高级的攻击是核裂变");

        ConcreteSubject concreteSubject = new ConcreteSubject();
        //三体舰队
        ThreeBodyFleet threeBodyFleet = new ThreeBodyFleet();
        //三体星
        ThreeBodyPlanet threeBodyPlanet = new ThreeBodyPlanet();
        //添加具体的观察者(三体舰队)
        concreteSubject.addObserver(threeBodyFleet);
        //添加具体的观察者(三体星)
        concreteSubject.addObserver(threeBodyPlanet);

        //调用通知(时间到了通知)
        concreteSubject.timeUp(earth);

        //因为人类新掌握了核聚变,紧急通知三体舰队(三体星不通知)
        earth.setWeapon("掌握了核聚变");
        concreteSubject.deleteObserver(threeBodyPlanet);
        concreteSubject.timeUp(earth);
    }
}
观察者模式优点

1、主题和具体的观察者之间松耦合的设计,使得观察者模式有很强的扩展性。
2、在客户端调用时候可以随意装配观察者

观察者模式的缺点

1、如果一个主题有非常多的直接或间接的观察者,则所有观察者都通知到会消耗很长时间。
2、如果多个主题之间有循环依赖的话,观察者可能 触发循环调用导致系统死掉。








以上是关于戏说模式之:观察者模式(三体)的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之单例模式

戏说设计模式 - 只有一个中国 - 单例模式

戏说设计

设计模式 行为型模式 -- 观察者模式(发布-订阅(Publish/Subscribe)模式)

php设计模式之观察者模式实例代码

戏说代理模式