浅谈Observer观察者模式

一、前言

观察者模式其实最好的名称应该是“发布订阅”模式,和我们现在大数据之中的发布订阅方式比较类似,但是也有区别的地方,在上一个设计模式,我们学习了仲裁者模式,其中当控件的状态发生改变的时候就会向仲裁者发出信息,让仲裁者进行仲裁,这其实和发布订阅非常的类似,但是用处是不一样的,仲裁者模式是用来解除复杂对象之间的相互调用的关系,从而独立出来进行开发,而观察者模式是在被观察者状态改变的时候被动的被唤醒进行相应的处理,两者的实现比较类似,比如都是被动唤醒的,但是思想和用处是不一样的,被唤醒之后的处理是不一样的。

1157683-20180630210022084-1133176611.png

二、代码

首先我们自己实现观察者模式,其次我们使用java已经实现好的观察者接口,然后来对比一下两者的不同。

(一)、自己实现观察者模式

package zyr.dp.observer;
import java.util.ArrayList;
import java.util.Iterator;
public abstract class NumberGenerator {
    private ArrayList observers=new ArrayList();
    public void add(Observer observer){
        observers.add(observer);
    }
    public void remove(Observer observer){
        observers.remove(observer);
    }
    public void notifyObserver(){
        Iterator it=observers.iterator();
        while(it.hasNext()){
            Observer object=(Observer)it.next();
            object.update(this);
        }
    }
    public abstract void execuate();
    public abstract int getNumber();
}
package zyr.dp.observer;
import java.util.Random;
public class RandomNumberGenerator extends NumberGenerator {
    private Random random=new Random();
    private int number;
    public int getNumber(){
        return number;
    }
    public void execuate() {
        for(int i=0;i<20;i++){
            number=random.nextInt(60);
            notifyObserver();
        }
    }
}
package zyr.dp.observer;
public interface Observer {
    public abstract void update(NumberGenerator object);
}
package zyr.dp.observer;
public class DigitalObserver implements Observer {
    public void update(NumberGenerator object) {
        System.out.println("DigitalObserver:"+object.getNumber());
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package zyr.dp.observer;
public class GraphObserver implements Observer {
    public void update(NumberGenerator object) {
        System.out.print("GraphObserver:");
        for(int i=0;i<object.getNumber();i++){
            System.out.print("*");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println();
    }
}
package zyr.dp.observer;
public class Main {
    public static void main(String[] args) {
        NumberGenerator numberGenerator=new RandomNumberGenerator();
        numberGenerator.add(new DigitalObserver());
        numberGenerator.add(new GraphObserver());
        numberGenerator.execuate();
    }
}

1157683-20180630211417746-1587568869.gif

由此可以看到当被观察者的状态发生改变的时候会主动通知观察者,使用notifyObserver的方法将自己的状态传递过去,因为是自己定义的被观察者的抽象类以及接口,因此使用起来非常的方便,代码也不是很多,能够按照自己的要求来完成更新操作,对比与仲裁者模式,被观察者是主动将自己的内容传递给观察者的,而仲裁者模式中,组员是本身就已经组合进了仲裁者之中,这也是一点不同。代码比较简单,这里被观察者使用了抽象类而不使用接口的原因是需要定义对观察者对象的委托,因此使用了抽象类,而观察者只用了update方法将被观察者通过参数传递的方式委托进来,因此使用接口更加清晰一点,当然抽象类也可以,只不过能使用接口的就不要使用抽象类,因为一个类只能继承一个父类,但是可以实现很多接口。

(二)、使用java自带的观察者模式

package zyr.dp.java;
import java.util.Observable;
import java.util.Random;
public class RandomNumberGenerator extends Observable {
    private Random random=new Random();
    private int number;
    public int getNumber(){
        return number;
    }
    public void execuate() {
        for(int i=0;i<20;i++){
            number=random.nextInt(60);
            setChanged();
            notifyObservers();
        }
    }
}
package zyr.dp.java;
import java.util.Observable;
import java.util.Observer;
public class DigitalObserver implements Observer {
    public void update(Observable object, Object arg) {
        System.out.println("DigitalObserver为:"+((RandomNumberGenerator)object).getNumber());
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package zyr.dp.java;
import java.util.Observable;
import java.util.Observer;
public class GraphObserver implements Observer {
    public void update(Observable object, Object arg) {
        System.out.print("GraphObserver为:");
        for(int i=0;i<((RandomNumberGenerator)object).getNumber();i++){
            System.out.print("*");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println();
    }
}
package zyr.dp.java;
import java.util.Observable;
public class Main {
    public static void main(String[] args) {
        Observable observable=new RandomNumberGenerator();
        observable.addObserver(new DigitalObserver());
        observable.addObserver(new GraphObserver());
        ((RandomNumberGenerator)observable).execuate();
    }
}

可以看到在java自定义的观察者模式中,首先要修改setChanged();来使notifyObservers生效,其次,传递的参数不是很灵活,需要强制转换成我们想要的东西,最后在使用的时候也需要强制转换,这是比较麻烦的,并且被观察者也是继承了抽象类Observable,不方便以后功能的扩展,如果以后再想继承其它的类就很麻烦了。我们自己设计的时候,可以使用某些方式把抽象类变成接口,不过也需要一定的操作。

三、《Head First 设计模式》读后感

1、观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

2、松耦合的威力。

设计原则:

找出程序中会变化的方面,然后将其和固定不变的方面相分离?

在观察者模式中,会改变的是主题的状态,以及观察者的数目和类型。用这个模式,你可以改变依赖于主题状态的对象,却不必改变主题,这就叫提前规划!

针对接口编程,不针对实现编程?

主题和观察者都使用接口:观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。这样可以让两者之间运行正常,又同时具有松耦合的优点。

多用组合,少用继承?

观察者模式利用“组合”将许多观察者组合进主题中,对象之间的这种关系不通过继承产生,而是在运行时利用组合的方式而产生的。

四、总结

通过观察者模式使得观察者和被观察者之间面向抽象编程,观察者不用知道自己观察的对象到底是谁的实例,只需要知道这个对象继承了被观察者的抽象类,因此当被观察者增加的时候,观察者可以不用修改。同样的,对于被观察者的实例来说,并不需要知道自己到底是呗哪一个观察者观察了,只需要知道观察自己的观察者肯定使用了观察者的接口,因此观察者和被观察者之间通过面向抽象编程提高了可扩展性,便于组件化。

我们可以看到在面向对象编程中能够使用委托的就不要使用继承,委托是弱关联,继承是强关联。并且将一些共同操作抽象出来放到抽象类之中去定义,在参数传递中不使用具体类型而是用接口或者抽象类,这样的设计思想便于组件化,具有可替代性。

五、拓展

Node.js是单进程单线程应用程序,但是因为V8引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。

Node.js几乎每一个API都是支持回调函数的。

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。

Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。

 

浅谈设计模式<最通俗易懂的讲解>

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值