设计模式之观察者模式

观察者模式主要用于当一个类对象改变时,多个对象做出相应的反应。例如,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,我需要开始战斗了。
我是民兵战士,我要协助红军战士们参加战斗了
我是老百姓,我要转移了。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值