观察者模式(行为型)
2016-05-07 22:36
357 查看
思考问题:在网上书店买一本书,当你支付成功后,会计需要开具发票,同时出纳员需要登记入账,同时配送员需要发货,如果由你来设计该下单业务,你应该如何设计?
解答:
1. 直接的,我们将设计书本类,会计类,出纳员类,配送员类,然后再里面添加相应的方法。
2. 当书本被购买成功(假设是sales方法)时,在sales方法内手动编码调用会计员的开发票方法、调用出纳员登记入账方法、调用配送员的配送方法,即可完成业务。
这种方法虽然简单的处理了业务,但耦合性很强;假如系统即将开发完成时,系统的客户突然说不需要出纳员登记入账功能了,或者需要在购买者支付成功后发信息通知购买者下单成功;如果按照上面的设计的话是不是必须改动源码了?
在一个事件发生时如果触发多个事件并行执行时就应该考虑观察者模式了,还以上面的为例子,使用观察者模式设计:
我们设计书本类,会计类,出纳员类,配送员类,然后再里面添加相应的方法。我们在书本Book类中添加一个容器,它装载那些当书本被销售时需要触发事件的对象(比如装会计对象、出纳员对象、配送员对象等)
当书本被购买成功(假设是sales方法)时,我们不再在sales方法内手动编码调用会计员的开发票方法或调用出纳员登记入账方法等。而仅仅是通知容器里面的对象(观察者),告诉它们书本钱已经收了,你们自己看着办。(比如逐个观察者调用sales(Book b)方法(观察者的通知方法);)
然后在每个观察者中,当sales(Book b)方法被触发时,自己执行自己应该执行的操作,比如会计开具发票,出纳员登记入账,配送员发货等,当客户的业务逻辑需要调整,比如取消会计开发票功能时,我们就取消往Book的那容器添加会计对象即可,如果需要添加下单成功时短信通知购买者,那么可以设计一个短信观察者添加到Book的容器中,然后短信观察者自身需要怎样发送就怎样实现就好了,拓展性好,体现了开闭原则(对拓展开放,对修改关闭)。
4.
图中使用BookI接口来提取公共方法,让电子书类(或纸质版书类)实现,然后在具体的电子书类中保存一个装载观察者的容器(当书本销售出去后就通知它们干他们应该干的,书本对象不需要知道他们干什么)
下面是实例代码:
BookI接口:
ElectronicBook:
ObserverI观察者接口:
会计观察者:
出纳员观察者:
快递员观察者:
测试类:
代码运行结果:
观察者模式优点:
观察者与被观察者(上面的电子书)之间只是抽象耦合,被观察者所知道的只是一个具体的观察者集合(observers)而无需知道观察者内部细节,所以很容易拓展,直接添加一个实现Observer接口的实例或移除一个实例即可修改业务功能。
(观察者模式适用于一个事件发生后同时触发其他事件发生的情况)
缺点:
1. 如果在观察者之间有循环依赖,被观察者会触发他们之间进行循环调用,导致系统崩溃。
2. 如果对观察者的通知是通过另外的线程进行异步投递,系统必须保证投递的顺序执行。
解答:
1. 直接的,我们将设计书本类,会计类,出纳员类,配送员类,然后再里面添加相应的方法。
2. 当书本被购买成功(假设是sales方法)时,在sales方法内手动编码调用会计员的开发票方法、调用出纳员登记入账方法、调用配送员的配送方法,即可完成业务。
这种方法虽然简单的处理了业务,但耦合性很强;假如系统即将开发完成时,系统的客户突然说不需要出纳员登记入账功能了,或者需要在购买者支付成功后发信息通知购买者下单成功;如果按照上面的设计的话是不是必须改动源码了?
在一个事件发生时如果触发多个事件并行执行时就应该考虑观察者模式了,还以上面的为例子,使用观察者模式设计:
我们设计书本类,会计类,出纳员类,配送员类,然后再里面添加相应的方法。我们在书本Book类中添加一个容器,它装载那些当书本被销售时需要触发事件的对象(比如装会计对象、出纳员对象、配送员对象等)
当书本被购买成功(假设是sales方法)时,我们不再在sales方法内手动编码调用会计员的开发票方法或调用出纳员登记入账方法等。而仅仅是通知容器里面的对象(观察者),告诉它们书本钱已经收了,你们自己看着办。(比如逐个观察者调用sales(Book b)方法(观察者的通知方法);)
然后在每个观察者中,当sales(Book b)方法被触发时,自己执行自己应该执行的操作,比如会计开具发票,出纳员登记入账,配送员发货等,当客户的业务逻辑需要调整,比如取消会计开发票功能时,我们就取消往Book的那容器添加会计对象即可,如果需要添加下单成功时短信通知购买者,那么可以设计一个短信观察者添加到Book的容器中,然后短信观察者自身需要怎样发送就怎样实现就好了,拓展性好,体现了开闭原则(对拓展开放,对修改关闭)。
4.
图中使用BookI接口来提取公共方法,让电子书类(或纸质版书类)实现,然后在具体的电子书类中保存一个装载观察者的容器(当书本销售出去后就通知它们干他们应该干的,书本对象不需要知道他们干什么)
下面是实例代码:
BookI接口:
package com.shusheng.observer; public interface BookI { public void sales();//销售书本的方法 public void addObserver(Observer observer);//添加观察者 public void removeObserver(Observer observer);//移除观察者 }
ElectronicBook:
package com.shusheng.observer; import java.util.Vector; /**电子书*/ public class ElectronicBook implements BookI{ private boolean sold = false;//表示是否已出售 private Vector<Observer> observers = new Vector<>();//装观察者的容器 /**销售书本的方法*/ @Override public void sales() { this.sold = true;//已售 System.out.println("书本已经出售"); for(Observer observer : observers){ observer.sales(this);//通知所有观察者书本已经销售了,让那些观察者看着办。 } } /**添加观察者*/ @Override public void addObserver(Observer observer) { this.observers.add(observer); } /**移除观察者*/ @Override public void removeObserver(Observer observer) { this.observers.remove(observer); } }
ObserverI观察者接口:
package com.shusheng.observer; /**观察者*/ public interface ObserverI { //该书本销售的方法通知观察者销售的book的信息 public void sales(ElectronicBook electronicBook); }
会计观察者:
package com.shusheng.observer; /**会计(观察者)*/ public class Accountant implements ObserverI{ /**通知的方法*/ @Override public void sales(ElectronicBook electronicBook) { this.account(); } /**会计开具发票函数*/ public void account(){ System.out.println("我是会计,我要开具发票啦"); } }
出纳员观察者:
package com.shusheng.observer; /**出纳员*/ public class Cashier implements ObserverI { @Override public void sales(ElectronicBook electronicBook) { System.out.println("我是出纳员,我要记账啦"); } }
快递员观察者:
package com.shusheng.observer; /**快递员(观察者)*/ public class Courier implements ObserverI { @Override public void sales(ElectronicBook electronicBook) { System.out.println("我是快递员,我要送出这本书啦"); } }
测试类:
package com.shusheng.observer; public class ObserverTest { public static void main(String[] args) { BookI bookI = new ElectronicBook();//电子书 ObserverI accountant = new Accountant(); ObserverI cashier = new Cashier(); ObserverI courier = new Courier(); bookI.addObserver(accountant); bookI.addObserver(cashier); bookI.addObserver(courier); bookI.sales();//出售书本 } }
代码运行结果:
观察者模式优点:
观察者与被观察者(上面的电子书)之间只是抽象耦合,被观察者所知道的只是一个具体的观察者集合(observers)而无需知道观察者内部细节,所以很容易拓展,直接添加一个实现Observer接口的实例或移除一个实例即可修改业务功能。
(观察者模式适用于一个事件发生后同时触发其他事件发生的情况)
缺点:
1. 如果在观察者之间有循环依赖,被观察者会触发他们之间进行循环调用,导致系统崩溃。
2. 如果对观察者的通知是通过另外的线程进行异步投递,系统必须保证投递的顺序执行。
相关文章推荐
- 20150307+Linux2+vi操作快捷键-01
- linux环境中cacti安装:
- 62. Unique Paths 唯一路径的条数
- Android 真机测试无法打印Log日志的解决方案
- Executor框架结构与主要成员(一)
- Building 'XXX' Gradle project info的android studio问题
- HDU 2648 Shopping
- hiho_1041 国庆出游
- 技术入股创业注意事项
- RHEL6.2下挂载光驱安装软件
- 2016/5/6 thinkphp ①框架 ② 框架项目部署 ③MVC模式 ④控制器访问及路由解析 ⑤开发和生产模式 ⑥控制器和对应方法创建 ⑦视图模板文件创建 ⑧url地址大小写设置 ⑨空操作空控制器 ⑩项目分组
- CSDN-markdown编辑器语法速查
- 使用深度搜索分析心理调查问卷的研究
- 在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?----转
- Charles的使用
- hdoj-2190-悼念512汶川大地震遇难同胞——重建希望小学
- android获取应用程序判断是系统程序还是应用程序并且判断在sd卡中还是内存中
- 《java入门第一季》之面向对象(形式参数和返回值问题深入研究1)
- 《java入门第一季》之面向对象(形式参数和返回值问题深入研究1)
- PB中表的修改对数据窗口和报表的影响的解决办法