head frist 设计模式学习之 JVM中的博物馆奇妙夜(观察者模式)

博物馆奇妙夜! 博物馆奇妙夜!博物馆奇妙夜!
重说三!!!
JVM看了《博物馆奇妙夜》电影之后,决定在自己家里开一个博物馆!毕竟需要什么new一下就好,博物馆很快就
开起来了,并且任命你为馆长(金馆长?),并且郑重的告诉了你作为馆长的职责:
1.接受JVM的节目单。
2.通知博物馆里的对象准备节目。
作为一名骄傲的oo程序员,你怎么能亲力亲为做这种事呢?于是你准备招一个下属,在java的世界里,你知道只需要new
一个就好,但是new之前需要一个class,没关系,写一个!
于是你看了一下节目单,有猴子,老鼠,和 橡皮鸭的节目,那么,do it!
class worker 
{
 
private String program_card;
public void program_cardChanged( )// 当节目单改变时调用此方法,这里不用管是如何调用的。
{
String program_card=getProgram_card();  // 这里假设已经实现好了
monkey.setProgram(program_card);  //把节目单给猴子,以下同理
mouse.setProgram(program_card);
ruberDuck.setProgram(program_card);
}
//其他方法。。。。
}
看起来这是一个很棒的下属,第一天的工作完成的非常棒!你开心的做别的事儿去了(LOL?),第二天两个电话打了进来
第一个是JVM打来的,他责备你:今天toy soldier的节目为什么没有上?
第二个是ruberDuck打来的,它向你抱怨:今天我不想演节目,干嘛给我节目单?

你怒气冲冲的找来你的worker ,大骂它一顿!但是它也很委屈,跟你说:
"我都是按照你写的来的啊,要错也是你错!"
你意识到可能是你错了,但是作为老板你是不会承认的,并且,你决定重新雇佣(new)一个工人,在这之前,我们先看看
第一个工人都犯了些什么错。
1.没有针对接口/超类编程,而是针对实现编程,导致当表演人员发生变化时,必须修改program_cardChanged()方法来应对
变化。
2.没有将变化封装。
3.monkey,mouse,ruberDuck等类都有setProgram( String program_card)方法,好像可以统一成接口。
是时候引入今天的主角了!
观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并
自动更新。
很明显,换到当前环境下就是:当worker对象中的program_card发生改变时,所有的想表演节目的对象都会接受
通知。
在解决上面的三个问题之前,我们先确定依赖:
在被依赖的对象(被观察者/主题)中,声明一个arraylist,用来存储依赖者(观察者)的实例,存储的过程我们称之为
注册(register)。
好了,我们正式开始oo设计!
1.设计被观察者接口。
通过上面的分析,我们知道被观察者需要具备的功能:注册,解注册和通知观察者,那么:
public interface Subject     //  主题/被观察者
{
public void registObserver(Observer o);  //注册
public void removeObserver(Observer o); //解注册
public void notifyObservers();  //通知
}
2.设计观察者接口
这里只需要一个方法供被观察者调用就好。
public interface Observer 


{
public void setProgram(String Program_card);
}

你让新招来的工人实现Subject:
public class Worker implements Subject
{
private Arraylist<Observer> observers;
private String program_card;
public Worker()
{
observers = new Arralisy<Observer> ();
}
public registerObserver(Observer o) //注册的过程就是将对象放到arraylist里
{
observers.add(o);
}
public removeObserver(Observer o) //解注册过程
{
int i=observers.indexOf(o);
if(i>=0)
{
observers.remove(i);
}
}
public void notifyObservers()  //遍历list,通知观察者
{
for(int i=0;i<observer,size();i++)
{
Observer o=observers.get(i);
o.setProgram(program_card);
}
}
public void program_cardChanged()
{
notifyObservers();    //当节目单更新时,通知观察者
}
 
}
让博物馆的演员们实现Observer,例如,RuberDuck:
public  class RuberDuck implements Observer
{
private String program_card;
private Subject worker;
public RuberDuck(Subject worker)
{
this.worker=worker;
work.registerObserver();
}
public void setProgram(string program_card)
{
this.program_card=program_card;
}
//其他方法省略。。。。。
}
一切看起来都是没问题的 
但是观察者模式到底为我们做了些什么呢?
答案 :松耦合
在观察者模式中,被观察者只需要知道观察者实现了Observer接口,并不知道观察者本身是什么,所以,我们可以独立的使用观察者(即复用)
而不用将两者捆绑在一起(紧耦合),反之,观察者也是如此。
作为一名oo程序员,你一定又发现了一个问题!那就是 String Program_card!既然是松耦合,那被观察者为什么知道观察者需要的数据类型呢?
对的,事实上被观察者不应该知道具体的数据类型,在java内置的观察者模式中,传递的数据类型是object,这样更符合我们松耦合的设定。
另外,从java内置的观察者模式中我们还可以对我们的观察者模式进行完善。
1.change。在我们的观察者模式中,只要数据一改变,就会通知所有的观察者,但有时候我们并不需要这么“灵敏”,所以可以在类中加入一个
改变位,当改变位=true 时,再通知观察者。(java内置的有相应的setChange和hasChange方法)。
2.推和拉。我们的观察者是采取推的方式传递数据,而拉则是 让 被观察者提供get方法,让观察者接到通知的时候去get,这两种方法各有利弊,
不再赘述。(同样,java内置的都有实现)
博主功力尚浅,博文中如有不当之处请读者海涵。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值