observer模式

观察者(Observer)模式的用途是定义对象之间的一对多依赖关系,因此,当一个对象的状态发生改变时,其所有依赖项都会得到通知,并自动更新。
这使得观察者适用于所有类型的通知需要


虽然实现的差异很明显,但在它们之间还是有一些相似之处。不论如何实现观察者,代码中都必须回答以下 4 个问题:
哪个对象是主体,哪个对象是观察者?
什么时候主体应当向它的观察者发送通知?
当接收到通知时,观察者应该做什么?
观察关系应当在什么时候开始,什么时候终止?
我将用这些问题作为框架,带您经历观察者(Observer)模式的 OO 实现。
角色定义
首先从标记器接口来分配角色开始。Observer 接口只定义了一个方法:update(),它对应着 Subject 发送通知时执行的操作。 Subject 承担着更多的职责。它的标记器接口定义了两个方法,一个用来跟踪观察者,另一个用来通知事件的那些观察者。
public interface Subject {
public void addObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}

一旦定义了这些角色,就可以把它们应用到系统中对应的角色上。
应用观察者角色
可以修改 BillingService,用以下少量代码实现观察者接口:
public class BillingService implements Observer {
//...
public void update(Subject subject) {
generateChargeFor((Playable) subject);
}
}

跟踪和通知观察者
一旦这项工作完成,就可以转移到两个 Subject。在这里,要对 Song 进行修改:

private Set observers = new HashSet();

public void addObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer o : observers) {
o.update(this);
}
}

现在面临的是一个不太让人高兴的任务:必须把 Subject 的这个实现剪切、粘贴到 Playlist 中。将 Subject 实现的一部分摘录到一个助手类中,这有助于缓解设计的弊端,但是仍然不足以完全消除它。
有没有更好的 OO 观察者?
这篇文章侧重在 Java 语言的 OO 模式实现上。读者可能想知道是否有特性更丰富的 OO 语言能够更好地解决观察者角色带来的这些令人头痛的问题。
现在已经把类调整到它们在模式中的角色上了。但是,还需要回过头来,在对应的事件发生时触发通知。Song 要求两个附加通知,而 Playlist 则需要一个:
//...in Song
public void play() {
System.out.println("Playing song " + getName());
notifyObservers();
}

public void showLyrics(){
System.out.println("Displaying lyrics for " + getName());
notifyObservers();
}

//...in Playlist
public void play() {
System.out.println("playing album " + getName());
for (Song song : songs) {
//...
}
notifyObservers();
}

需要牢记的是,虽然示例系统只需要一个状态改变通知,但是实际的系统可能许多许多通知。例如,我曾经开发过一个应用程序,该应用程序要求在 更改购物车状态时发送观察者风格的通知。为了做到这一点,我在购物车和相关对象中的 10 个以上的位置应用了通知逻辑。
随着各个角色准备好参与到模式中,剩下来要做的就是把它们连接起来。
启动观察关系
为了让 BillingService 开始观察 Song 或 Playlist,需要添加胶水代码,由它调用 song.addObserver(billingService)。这个要求与 第 1 部分 中描述的适配器和修饰器的胶水代码的要求类似。除了影响参与者之外,模式还要求对系统中不确定的部分进行修改,以便激活模式。清单 2 包含的代码模拟了客户与系统的交互,并整合了这个胶水代码,胶水代码是突出显示的。清单 2 还显示了示例系统的输出。

清单 2. 连接主体和观察者(并试验系统)的客户代码
public class ObserverClient {
public static void main(String[] args) {
BillingService basicBilling = new BillingService();
BillingService premiumBilling = new BillingService();

Song song = new Song("Kris Kringle Was A Cat Thief");
song.addObserver(basicBilling);


Song song2 = new Song("Rock n Roll McDonald's");
song2.addObserver(basicBilling);
//this song is billed by two services,
//perhaps the label demands an premium for online access?
song2.addObserver(premiumBilling);

Playlist favorites = new Playlist("Wesley Willis - Greatest Hits");
favorites.addObserver(basicBilling);

List songs = new ArrayList();
songs.add(song);
songs.add(song2);
favorites.setSongs(songs);

favorites.play();

song.showLyrics();
}
}
//Output:
playing playlist Favorites
Playing song Kris Kringle Was A Cat Thief
generating charge for : Kris Kringle Was A Cat Thief
Playing song Rock n Roll McDonald's
generating charge for : Rock n Roll McDonald's
generating charge for : Rock n Roll McDonald's
generating charge for : Favorites
Displaying lyrics for Kris Kringle Was A Cat Thief
generating charge for : Kris Kringle Was A Cat Thief
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值