设计模式之观察者模式

来源:互联网 发布:凭都网软件 编辑:程序博客网 时间:2024/06/03 20:59

观察者模式主要用于当一个类对象改变时,多个对象做出相应的反应。例如,Android广播使用的就时观察者模式。当一些对象接受到消息,做出一系列的反应。

现在,我们模拟一个观察者的使用场景。
那是长征期间,红军战士为了躲避老蒋的追击,每到一处都会有警卫站岗,一旦警卫发现敌情就会通知他的战友们准备战斗,当他的战友得到通知时就会做出相应的行动。
在这里,警卫是通知者,他的战友们就是观察者, 如何实现呢?看下面的代码

定义一个红军类

//红军类public class RedArmy {    private String name ;    public RedArmy(String name){        this.name = name ;    }    //进行相关更新操作    public void update(){        System.out.println("我是"+name+",我接收到消息了。");    }    public String getName(){        return this.name ;    }}

定义一个警卫类

//警卫类public class Guard {    private List<RedArmy> redArmies ;    public Guard(){        redArmies = new ArrayList<>();    }    //增加一个将要通知的战友    public void addRedArmy(RedArmy redArmy){        this.redArmies.add(redArmy);    }    //如果一个战友牺牲了,就不再通知他了    public void removeArmy(RedArmy redArmy){        this.redArmies.remove(redArmy);    }    public void notifyArmy(){        for (RedArmy redArmy : redArmies) {            redArmy.update();  //进行相应的操作        }    }}

测试类

public class Test {    public static void main(String[] args) {        RedArmy r1 = new RedArmy("红军战士1"); //实例化一个红军战士        RedArmy r2 = new RedArmy("红军战士2");//实例化一个红军战士        Guard guard = new Guard(); //实例化一个警卫        guard.addRedArmy(r1); //将红军战士1作为警卫的通知对象        guard.addRedArmy(r2); //将红军战士2作为警卫的通知对象        guard.notifyArmy();   //通知红军战士    }}

运行结果

我是红军战士1,我接收到消息了。我是红军战士2,我接收到消息了。

从程序运行上,已经完全达到我们预期的效果,也满足我们的要求。但是,此时如果警卫不在,让侦察兵来通知,接下来我们该怎么做呢?对于码农的我们,抡起键盘就是再写一个和警卫类似的一个类。那么如果再换人呢,还要再写吗?此时我们应该想到面向对象中的抽象的特性了。我们可以抽象出一个通知类,可以进行通知。无论是警卫还是侦察兵,只要实现了抽象就可以了。其实这就是所谓的高大上的依赖抽象而不依赖具体。

定义一个抽象通知者类

//抽象的通知者public abstract class Subject {    protected List<RedArmy> redArmys;    public Subject() {        this.redArmys = new ArrayList<>();    }    public void addRedArmy(RedArmy redArmy){        this.redArmys.add(redArmy);    }    public void removeRedArmy(RedArmy redArmy){        this.redArmys.remove(redArmy);    }    public void notifyGuard(){        for (RedArmy redArmy:redArmys) {            redArmy.update();        }    }}

修改警卫类,继承抽象通知者类

//警卫类public class Guard extends Subject{}

测试类

public class Test {    public static void main(String[] args) {        RedArmy r1 = new RedArmy("红军战士1"); //实例化一个红军战士        RedArmy r2 = new RedArmy("红军战士2");//实例化一个红军战士        //这里直接sj = new Guard();如果换成侦察兵,只需改动sj = new 侦察兵();就可以了。        Subject sj = new Guard(); ////实例化一个警卫        sj.addRedArmy(r1); //将红军战士1作为警卫的通知对象        sj.addRedArmy(r2); //将红军战士2作为警卫的通知对象        sj.notifyArmy();   //通知红军战士    }}

通过我们的第一步修改已经完成了通知者依赖抽象,现在看看代码还有什么问题了吗?没错,还是存在着依赖具体的缺陷。假设现在追击的不是老蒋而是小日本了,小日本可是非常毒的,他们不仅杀害红军战士,还伤害老百姓,所以此时警卫还要通知老百姓。代码怎么改呢?难道我们在通知者中再加一个List<老百姓>的集合吗?确实是可以,但是如果还要再去通知民兵呢?还要再修改通知者吗,这已经违背了设计模式的开放-封闭原则(对扩展开放,对修改关闭)我们尽量不修改就不去修改。
分析一下,无论是红军战士还是老百姓,还是民兵他们在这都是观察者,就是当他们一旦得到消息就会行动。所以我们抽象出一个观察者类。

抽象观察者类

//抽象观察者类public abstract class Observer {    protected String name ;    public Observer(String name){        this.name = name ;    }    public abstract void update();}

修改红军战士类,继承抽象观察者类即可。

//红军类public class RedArmy extends Observer{    public RedArmy(String name) {        super(name);    }    @Override    public void update() {        System.out.println("我是"+name+",我需要开始战斗了。");    }}

添加老百姓类

//老百姓类public class Civilian extends Observer {    public Civilian(String name) {        super(name);    }    @Override    public void update() {        System.out.println("我是"+name+",我要转移了。");    }}

添加民兵类

//民兵类public class Militia extends Observer{    public Militia(String name) {        super(name);    }    @Override    public void update() {        System.out.println("我是"+name+",我要协助红军战士们参加战斗了");    }}

最后再修改通知者类,让通知者依赖观察者的抽象,而不是具体实现

//抽象的通知者public abstract class Subject {    //依赖观察者的抽象    protected List<Observer> observers ;    public Subject() {        this.observers = new ArrayList<>();    }    public void addObserver(Observer observer){        this.observers.add(observer);    }    public void removeObserver(Observer observer){        this.observers.remove(observer);    }    public void notifyArmy(){        for (Observer observer:observers) {            observer.update();        }    }}

测试类

public class Test {    public static void main(String[] args) {        Observer r1 = new RedArmy("红军战士1"); //实例化一个红军战士        Observer r2 = new RedArmy("红军战士2");//实例化一个红军战士        Observer m1 = new Militia("民兵战士"); //实例化一个民兵战士        Observer c1 = new Civilian("老百姓");  //实例化一个老百姓        Subject sj = new Guard(); ////实例化一个警卫        sj.addObserver(r1); //将红军战士1作为警卫的通知对象        sj.addObserver(r2); //将红军战士2作为警卫的通知对象        sj.addObserver(m1);//将民兵战士作为警卫的通知对象        sj.addObserver(c1);//将老百姓作为警卫的通知对象        sj.notifyArmy();   //通知观察者    }}

运行结果

我是红军战士1,我需要开始战斗了。我是红军战士2,我需要开始战斗了。我是民兵战士,我要协助红军战士们参加战斗了我是老百姓,我要转移了。

我们可以看到完全可以实现我们的功能,当警卫发现出现敌情时,可以同时通知老百姓,红军战士,民兵,而他们由于身份不同,责任不同,所以做出了不同的选择。

现在即使就是侦察兵和警卫都不在了,我们只需要有一个类继承了通知者就完全可以取代警卫的工作。

原创粉丝点击