在GOF的设计模式一书中将观察者定义为一种对象的行为模式,又叫做发布-订阅模式(Publish/Subscribe)、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
Java的标准库中包含了一个Observer接口和一个Observable类。
Observer接口很简单,只包含了一个update方法:
public interface Observer {
void update(Observable o, Object arg);
}
Observable类的大纲如下
Observable类自身维护了一个包含Observer的列表,和一个表示自身状态的changed标志,当自身状态发生变化时就调用notifyObservers通知所有注册的观察者。notifyObservers方法通过对调用每一个成员的Observer接口的update方法来实现对观察者的通知。
使用这种模式的例子在网上已经有很多了,这里不再具体举例,但需要指出的是在客户代码使用Java标准库提供的Observer/Observable对来实现观察者模式时需要自己编写一个继承Observable类的被观察者和一个实现Observer接口的观察者。这种方式有一个缺陷,因为Java语言是单继承的,一旦客户代码中的被观察者已经继承了一个其他的类则无法再次继承Observable类,这也大大的限制了这种模式的广泛使用。
在GOF一书中则描述了另一种使用观察者的模式,即将观察者和被观察者全部做成抽象接口,下面是这种模式的静态类图。
抽象被观察者提供注册和删除观察者对象的接口,一个通知观察者的接口。抽象观察者在被观察者状态发生变化并得到通知时提供一个更新自己的接口。具体被观察者和具体观察者是对抽象接口的具体实现。其中具体被观察者维护一个所有注册的观察者的列表,而观察者的update方法接受一个指向被观察者的引用。
观察者模式所适用的一个很重要的场景是当一个对象必须通知其他对象,而它又不能假定其它对象是谁。也就是说,你不希望这些对象是紧密耦合的。这里通过使用接口来达到解耦的目的。这种观察者模式的应用使用接口而不是类解决了Java单继承的问题,这种模型通过GOF一书而得到广为流传,网络上的例子很多,这里也不具体举例了。但是我们也看到,由于Observer接口只有一个update方法,也就说是当观察者接受到通知它只能作出同样的回应。在一个事件-触发模型中,由于观察者(或者说事件监听者)需要对不同的事件作出回应,那这种模型就不再适用。就算用起来也会显得很繁琐,比如在具体观察者的update方法中指定参数类型,或者使用反射,又或者传入一个参数来表明事件的类型,但不论如何都不是一种很好的实现方式。而可以复用的只有两个接口,每次使用的时候必须要实现两个具体类,没能达到很高的复用性。
下面介绍一种新的Observer模式的实现方法。这里使用了泛型模板,通过参数化Observer接口来实现任意定制更新方法。另外还引入了一个ObserverOp的接口,将Observer Operation的操作抽象,使得观察者与被观察者解耦。
/** Observable接口代码 */
public interface Observable<T> {
public static interface ObserverOp<T>
{
public void apply (T observer);
}
public void addObserver(T observer);
public void deleteObserver(T observer);
public void notifyObservers(ObserverOp<T> obop);
}
每一个被观察者都要实现这个接口则显得比较繁琐,所以这里提供了一个默认实现。
/** Observable接口的默认实现代码 */
public class DefaultObservable<T> implements Observable<T> {
private List<T> obs;;
public DefaultObservable(){
obs = new ArrayList<T>();
}
public void addObserver(T observer) {
obs.add(observer);
}
public void deleteObserver(T observer) {
obs.remove(observer);
}
public void notifyObservers(Observable.ObserverOp<T> obop) {
Iterator<T> iterator = obs.iterator();
while (iterator.hasNext()){
obop.apply(iterator.next());
}
}
}
下面举例说明这种观察者模式的使用,假如我们有一个Session类,当Session的状态发生变化时需要通知客户代码,并假设状态的变化有激活和静默两种,这样我们就有了一个SessionObserver接口。
/** SessionObserver接口的代码 */
public interface SessionObserver {
public void SessionActivate(Session session);
public void SessionPassivate(Session session);
}
同时我们也有一个对应的Session类。
/** Session类的代码 */
public class Session {
private Observable<SessionObserver> obs = new DefaultObservable<SessionObserver>();
public void addSessionObserver(SessionObserver observer){
obs.addObserver(observer);
}
public void Activate(){
//do activate
Notifier noty = new Notifier(SESSION_ACTIVATE);
obs.notifyObservers(noty);
}
public void Passivate(){
//do passivate
Notifier noty = new Notifier(SESSION_PASSIVATE);
obs.notifyObservers(noty);
}
private class Notifier implements Observable.ObserverOp<SessionObserver>{
private int code;
public Notifier(int code){
this.code=code;
}
public void apply(SessionObserver obs){
switch (code){
case SESSION_ACTIVATE:
obs.SessionActivate(Session.this);
break;
case SESSION_PASSIVATE:
obs.SessionPassivate(Session.this);
break;
}
}
}
public static final int SESSION_ACTIVATE = 1;
public static final int SESSION_PASSIVATE = 2;
}
在这里我们内置了一个Notifier类,这个类实现了ObserverOp接口,将我们所有的Observer Operation操作都包含了进去,使得其余部分的代码十分简洁。在这里Notifier类实际上实现了设计模式中另一个strategy(策略)模式,这个stragety(策略)将相关的操作算法封装在了一个类里。对于不同的Observer接口可以十分方便的替换我们的算法。下面是客户代码,当Session被激活或者静默时客户代码被自动通知并作出反应。
/** 客户代码 */
public class Client implements SessionObserver {
public void SessionActivate(Session session) {
System.out.println("Session has been activated...");
}
public void SessionPassivate(Session session) {
System.out.println("Session has been passivated...");
}
public static void main (String[] args){
Client client = new Client();
Session session = new Session();
session.addSessionObserver(client);
session.Activate();
session.Passivate();
}
}
通过观察上面的例子我们可以看到,使用这种观察者模式的模型,当被观察者被通知时,可以根据通知的内容调用相应的方法,在这里就是当Session被激活时调用SessionActivate方法,当Session被静默时调用SessionPassivate方法,而不仅仅是一个简单的update方法。但是这种模型也有一个问题,就是在这里Session是一个被观察者的身份,但是因为使用了泛型的模板而无法继承DefaultObservable类,或实现Observable接口,使得IS-A关系变成了HAS-A,逻辑上不是那么的清晰。解决的办法是取消Observable接口和DefaultObservable类,使用一个ObserversList来代替,在Session中直接维护一个ObserversList,那么在逻辑上Session自然就成了一个被观察者。
下面我们来看下新模型下的ObserversList类和修改过的Session类。
/** ObserverList的实现代码 */
public class ObserverList<T> extends ArrayList<T> {
public static interface ObserverOp<T>
{
public void apply (T observer);
}
public void addObserver(T observer){
add(observer);
}
public void deleteObserver(T observer){
remove(observer);
}
public void notifyObservers(Observable.ObserverOp<T> obop) {
int count = size();
if (obs == null ){
obs = (T[])new Object[count];
}
toArray(obs);
for(int i=0;i<count;i++){
obop.apply(obs[i]);
}
}
private T[] obs;
}
/** 修改过的Session类的实现代码 */
public class Session {
private ObserverList<SessionObserver> obs = new ObserverList<SessionObserver>();
public void addSessionObserver(SessionObserver observer){
obs.addObserver(observer);
}
public void Activate(){
//do activate
Notifier noty = new Notifier(SESSION_ACTIVATE);
obs.notifyObservers(noty);
}
public void Passivate(){
//do passivate
Notifier noty = new Notifier(SESSION_PASSIVATE);
obs.notifyObservers(noty);
}
private class Notifier implements Observable.ObserverOp<SessionObserver>{
private int code;
public Notifier(int code){
this.code=code;
}
public void apply(SessionObserver obs){
switch (code){
case SESSION_ACTIVATE:
obs.SessionActivate(Session.this);
break;
case SESSION_PASSIVATE:
obs.SessionPassivate(Session.this);
break;
}
}
}
public static final int SESSION_ACTIVATE = 1;
public static final int SESSION_PASSIVATE = 2;
}
在这个新的模型下,ObserverList继承自ArrayList,而Session类里维护了这个包含所有观察者的列表,所以在逻辑上自然而然的成立了IS-A Observable的关系,其他代码都维持不变。现在ObserverList类可以被放到通用的类库中被反复使用,而客户则可以根据需要定制自己的Observer接口,并将相对应的算法操作封装在一个具体的ObserverOp类中。
- 大小: 40.1 KB
- 大小: 54.2 KB
分享到:
相关推荐
观察者模式最好的诠释 模式编程中的观察者模式delphi代码
6.3.4 观察者模式(observer模式) 6.3.5 命令模式(command模式) 6.3.6 备忘录模式(memento模式) 6.3.7 迭代子模式(iterator模式) 6.3.8 访问者模式(visitor模式) 6.3.9 调停者模式(mediator模式) ...
设计模式,如工厂模式、单例模式、观察者模式等,是软件设计中的通用解决方案。它们是经过时间和实践检验的,可以提高代码可读性、可维护性和可扩展性。将设计模式应用于C++编程,可以帮助开发者更好地组织代码,...
10. **设计模式**:源码中可能会采用各种设计模式,如工厂模式、单例模式、观察者模式等,帮助你理解和应用软件设计原则。 通过对《Delphi深度探索(第二版)》源码的深入学习,开发者不仅能掌握Delphi语言的基本...
10. 高级设计模式:可能涉及到单例模式、工厂模式、观察者模式等常见的设计模式及其在C#中的实现。 以上只是部分可能涵盖的主题,实际的《C#编程深度探索_PartII》PDF文档会更详尽地探讨这些知识点,并通过实例和...
6. **高级设计模式**:深入讨论设计模式在C#中的应用,如工厂模式、单例模式、观察者模式、装饰器模式等,以及如何在实际项目中灵活运用。 7. **单元测试与持续集成**:介绍如何编写单元测试,使用测试框架如NUnit...
教师的角色是引导者和协助者,他们需要不断更新教学观念,设计符合学生兴趣和需求的“研学”活动,传授有效的学习方法,并鼓励学生分享和反思,以此推动学生从“游学”向深度学习的转变,提升他们的实践能力和创新...
行为型模式则关注对象之间的交互和职责分配,如策略模式、责任链模式和观察者模式。 在Java中,设计模式的应用能够提高代码的可读性、可维护性和可扩展性。例如,单例模式保证一个类只有一个实例,常用于控制共享...
与浅表学习和虚假学习相对,深度学习关注学生在课堂中的真实学习体验,鼓励他们积极参与、主动探索和自我表达。 【学情观察】 学情观察是一种专业教学评估方法,它改变了传统听课模式,不再仅仅关注教师的表现,...
在幼儿探索游戏的实践中,教师不仅是引导者,更应当是观察者和反馈者。通过精心设计和实施的游戏,教师可以激发幼儿的内在动力,帮助他们在快乐的游戏中学习,形成独立思考和解决问题的能力,为他们的未来发展打下...
他们需要在教师的引导下,通过小组讨论、实验观察等方式,深入探索概念的来源和内在逻辑。这个过程是十分关键的,因为它直接关系到学生能否真正进入深度学习的状态。同时,教师还要帮助学生暴露和处理他们的前概念,...
本研究采用了程序性扎根理论作为研究方法,通过对基层医务人员、医院工作人员、政府人员和养老机构负责人的深度访谈以及参与式观察,初步构建了一个以多学科资源整合为核心的居家老年痴呆患者及照护者医疗服务模式。...
大数据营销模式探索主要聚焦于如何运用大数据来改变传统的营销策略,构建更加精细化、实时化的消费者体验。这种模式的出现是对传统营销概念的颠覆,它强调的不再仅仅是“销售”,而是关注消费者的“购买”行为和体验...
例如,工厂模式、单例模式和观察者模式等,都是被广泛接受并应用于实际项目中的经典设计模式。理解并熟练运用这些模式,能够提高代码的可读性、可维护性和复用性。 在国内,由于软件行业起步相对较晚,早期的设计...
教师的角色则转变为引导者和支持者,他们需要不断更新知识库,创新教学方法,以适应深度学习模式,同时关注学生的心理状态,激发他们的学习兴趣和独立思考意识。 【小学数学教学中深度学习实践模式策略】 2.1 创建...
在这种模式中,学生在课堂上不再是被动接收信息的对象,而是通过积极的探索和实践,成为知识的主动建构者。在生物学教育中,这一模式特别有助于提升学生对生物学概念的理解和实验技能的掌握。 以“酶的特性”这一...
在总结SpaceX商业模式和科技行业卫星互联网的发展趋势时,中金公司的这份报告为我们提供了丰富的信息,它不仅包含了技术层面的深度解析,还包括了商业模式、行业竞争、以及市场发展的多角度观察。通过这份报告,我们...
云游戏的发展历程可以分为四个阶段:从概念提出到技术探索(2000-2009),技术探索到技术成熟(2010-2018),技术成熟到商业可行(2019-2020),以及当前的商业发展阶段。在此期间,各大科技公司如Sony、Google、...
设计模式之 Observer(观察者) 介绍如何使用 Java API 提供的现成 Observer 设计模式之 Iterator(迭代器) 这个模式已经被整合入Java的Collection.在大多数场合下无需自己制造一个Iterator,只要将对象装入...
包括职责链模式(Chain of Responsibility)、命令模式(Command)、解释器模式(Interpreter)、迭代器模式(Iterator)、中介者模式(Mediator)、备忘录模式(Memento)、观察者模式(Observer)、状态模式...