`
phpxiaoxin
  • 浏览: 249135 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

观察者模式 Observer

阅读更多

最近学习了观察者模式,以前怎么也想不明白,松耦合怎么实现,两个类A,B中的方法c,d之间互相调用,必然需要通过B.d的方式,不然怎么实现功能独立?学习了观察者,哈哈,终于知道怎么就实现松耦合了。设计模式还是很有用且有趣的。

首先,你必须明白设计模式只是一种模式,并不能跨越一些东西,实现不调用B.d的方法实现B.d的功能。


简单来说,观察者模式就是:老鼠想偷东西,一但猫叫,老鼠就跑(观察模式的详细概念,请阅读最后的参考文章)。java语言本身支持观察者模式,那么就有cat.call(), mouse.run(),然后两个通过什么方式关联呢?

1.猫叫的时候,需要发出一个信号,表示,我要叫了,或者,我已经叫了。(你说这猫是不是有点白痴丫,恩,的确有点)对应方法如下:

setChanged();
notifyObservers("嗷嗷");


2.这个时候老鼠有一个固定的方法 update();就受到了信息,并且执行该方法。然后的代码或者被update调用,或者干脆直接写到run里面。


3.建立以上关联的就是 Observer 和 Observable,其中

老鼠,也就是观察者要实现 Observable接口:

public class Mickey implements Observer //这里是米奇老鼠,其实这里说“米奇”是不对的,先不管。

而这个Observer有一个update的方法,需要实现。


猫,也就是被观察的对象则要继承Observable类:

public class Cat extends Observable

继承之后,默认就有了一下重要的方法:

setChanged(); //设置改变
notifyObservers(); //通知改变

addObserver(); //通过这个方法增加一个观察者对象,让观察者和观察的对象关联起来。其实就是给被观察的对象增加一个观察者


下面看看具体的代码:

/**
 * 观察者模式学习-猫,被观察的对象
 * @author <a href="mailto:phpxiaoxin@gmail.com">phpxiaoxin</a>
 */

public class Cat extends Observable{

    public Cat(String name){
        this.name = name;
    }

    private String name;
    public void call(){
        this.setChanged();//this statement is need
        System.out.println("谁把我吵醒了!");
        this.notifyObservers("嗷嗷");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


/**
 * 哈哈米奇在此
 * @author <a href="mailto:phpxiaoxin@gmail.com">phpxiaoxin</a>
 */

public class Mickey implements Observer{

    public void update(Observable o, Object arg) {
        this.call(o, arg);
    }
    private void call(Observable o, Object arg){
        cat = (Cat) o;//这是拉过来的数据??不利于松耦合
        String msg = (String) arg;//这是推送过来的数据,便于松耦合

        System.out.println("this message comes from the Observable:" + arg);
        System.out.println("oh no,the creazy " + cat.getName() + " is calling ,i need to run.");
    }
    private Cat cat;

}


/**
 * 米奇开始捉弄猫了
 * @author <a href="mailto:phpxiaoxin@gmail.com">phpxiaoxin</a>
 */

public class MickeyPlayCat {

    public static void main(String[] args){

        Cat cat = new Cat("波斯猫");
        Mickey mickey = new Mickey();
        cat.addObserver(mickey);//这句让老鼠成为猫的观察者
        cat.call();
        System.out.println("完成观察者基本的学习");
    }
}
 




关于米奇老鼠中的推拉的注释我不确定我的理解是正确的 。关于推拉是这样的:


其实猫叫,要让老鼠知道,有两种方式,一种是猫叫的时候(之前或者之后都可以),通知一下老鼠,这就是所谓的推(pull)

而另外一种方式是:老鼠不断的主动看一下猫是否叫了,虽然猫如果真的要叫,老鼠会听见,这里你可以认为是猫的一种状态,比如说猫醒了,老鼠不断观察,看看猫是否醒,这就是拉了(push)


这两种方式各有利弊,详细分析大家可以看看下面的“观察者和被观察对象的对话”的文章。也挺好玩的。

http://dev.csdn.net/author/lin_bei/3a02cdf586ed47c1ac88a9d57c9e13f4.html


但是网上大部分例子都是说如何通知,也就是推(pull),而没有说如何去通过拉的方式。不知道我注释理解的对不对,个人估计8成是错的。知道是错的情评论指正,谢谢:)


最后回到开始的问题,他是怎么实现松耦合的?很简单,下面是来自java的 Observable对象 notifyObservers方法的具体实现,大家一看就明白了。

public void notifyObservers(Object arg) {
        Object[] arrLocal;

    synchronized (this) {
        if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
 




其中((Observer)arrLocal[i]).update(this, arg);表明,在运行的时候,其实还是猫调用了老鼠的update方法。只不过他通过接口实现了老鼠和猫的松耦合。所以,设计模式不能跨越一些东西,他只是一种模式,是一种巧妙的方法。


需要说明的是其内部通过synchronized(同步)代码块的方式来加锁对象,实现同步。我也是第一此知道synchronized是什么,详细资料可以参考下面的文章:

http://hi.baidu.com/lynuhuoqubing/blog/item/a9450009517b5e87d1581bad.html


他里面的比喻很好玩,这里单独引用出来:

写道
同步就是简单的说我用的时候你不能用,大家用的要是一样的就这样!
比如说有只苹果很好吃,我拉起来咬一口,放下,你再拉起咬一口,这就同步了,要是大家一起咬,呵呵,那就结婚吧,婚礼上常能看到这个,也不怕咬着嘴,嘻嘻嘻!

 

关于观察者模式,大家还可以参考以下文章:

 

http://baike.baidu.com/view/1854779.htm 这个是用php语言举的例子,也是面向对象的,顺便学习一下php也不错

http://blog.hunan2s.com/?p=408

http://www.iteye.com/topic/249722

http://www.xue5.com/itedu/200702/91856.html

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics