最近学习了观察者模式,以前怎么也想不明白,松耦合怎么实现,两个类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