经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
大话设计模式笔记(十一)の观察者模式
来源:cnblogs  作者:callmeDevil  时间:2019/7/29 9:11:27  对本文有异议

举个栗子

问题描述

几个同事上班期间看股市行情,让前台MM帮忙看着老板什么时候过来查岗,老板进门的时候MM就拨电话给其中一个同事,于是所有同事都知道了,再继续工作。。。

简单实现

前台秘书MM

  1. /**
  2. * 前台秘书MM
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public class Secretary {
  6. // 同事列表
  7. private List<StockObserver> observers = new ArrayList<>();
  8. private String action;
  9. // 增加
  10. public void attach(StockObserver observer){
  11. // 有几个同事请前台帮忙,于是就给集合增加几个对象
  12. observers.add(observer);
  13. }
  14. // 通知
  15. public void call(){
  16. // 待老板来了,就给所有登记的同事们发通知
  17. for (StockObserver observer : observers) {
  18. observer.update();
  19. }
  20. }
  21. public String getAction() {
  22. return action;
  23. }
  24. public void setAction(String action) {
  25. this.action = action;
  26. }
  27. }

看股票同事

  1. /**
  2. * 看股票同事
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public class StockObserver {
  6. private String name;
  7. private Secretary sub;
  8. public StockObserver(String name, Secretary sub){
  9. this.name = name;
  10. this.sub = sub;
  11. }
  12. public void update(){
  13. System.out.println(String.format("%s %s 关闭股票行情,继续工作!", sub.getAction(), name));
  14. }
  15. }

测试

  1. public class Test {
  2. public static void main(String[] args) {
  3. // 前台妹子
  4. Secretary mm = new Secretary();
  5. // 看股票的同事
  6. StockObserver observer1 = new StockObserver("哪路托", mm);
  7. StockObserver observer2 = new StockObserver("啥是gay", mm);
  8. // 前台妹子记下两位同事
  9. mm.attach(observer1);
  10. mm.attach(observer2);
  11. // 发现老板
  12. mm.setAction("老板回来了!");
  13. // 通知两个同事
  14. mm.call();
  15. }
  16. }

测试结果

  1. 老板回来了! 哪路托 关闭股票行情,继续工作!
  2. 老板回来了! 啥是gay 关闭股票行情,继续工作!

存在问题

  • “前台MM”和“看股票同事”互相耦合
  • 如果还有人想看NBA直播,那只能改动“前台MM”,不符合开放-封闭原则
  • 其次应该遵循依赖倒转原则,让两者之间不相互依赖

简单实现2

抽象观察者

  1. /**
  2. * 抽象观察者
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public abstract class Observer {
  6. protected String name;
  7. protected Secretary sub;
  8. public Observer(String name, Secretary sub) {
  9. this.name = name;
  10. this.sub = sub;
  11. }
  12. public abstract void update();
  13. }

前台秘书MM

  1. /**
  2. * 前台秘书MM
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public class Secretary {
  6. // 同事列表
  7. private List<Observer> observers = new ArrayList<>();
  8. private String action;
  9. // 增加
  10. public void attach(Observer observer) { //针对抽象编程,减少了与具体类的耦合
  11. observers.add(observer);
  12. }
  13. // 减少
  14. public void detach(Observer observer) { //针对抽象编程,减少了与具体类的耦合
  15. observers.remove(observer);
  16. }
  17. // 通知
  18. public void call() {
  19. for (Observer observer : observers) {
  20. observer.update();
  21. }
  22. }
  23. public String getAction() {
  24. return action;
  25. }
  26. public void setAction(String action) {
  27. this.action = action;
  28. }
  29. }

看股票的同事

  1. /**
  2. * 看股票的同事
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public class StockObserver extends Observer {
  6. public StockObserver(String name, Secretary sub) {
  7. super(name, sub);
  8. }
  9. @Override
  10. public void update(){
  11. System.out.println(String.format("%s %s 关闭股票行情,继续工作!", sub.getAction(), name));
  12. }
  13. }

看NBA的同事

  1. /**
  2. * 看 NBA 的同事
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public class NBAObserver extends Observer {
  6. public NBAObserver(String name, Secretary sub) {
  7. super(name, sub);
  8. }
  9. @Override
  10. public void update() {
  11. System.out.println(String.format("%s %s 关闭NBA 直播,继续工作!", sub.getAction(), name));
  12. }
  13. }

测试代码同上

存在问题

其实“前台MM”也应该抽象出来,如果老板回来时,MM来不及电话了,于是通知大家的任务变成谁来做?是的,这时候是老板本人变成了通知者。

观察者模式

定义

又叫做发布-订阅模式定义了一种一对多的依赖关系,让多个观察者对象同事监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

UML图

代码实现

通知者接口

  1. /**
  2. * 通知者接口
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public interface Subject {
  6. void attach(Observer observer);
  7. void detach(Observer observer);
  8. void call();
  9. String getAction();
  10. void setAction(String action);
  11. }

老板

  1. /**
  2. * 老板
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public class Boss implements Subject {
  6. // 同事列表
  7. private List<Observer> observers = new ArrayList<>();
  8. private String action;
  9. @Override
  10. public void attach(Observer observer) {
  11. observers.add(observer);
  12. }
  13. @Override
  14. public void detach(Observer observer) {
  15. observers.remove(observer);
  16. }
  17. @Override
  18. public void call() {
  19. for (Observer observer : observers) {
  20. observer.update();
  21. }
  22. }
  23. public String getAction() {
  24. return action;
  25. }
  26. public void setAction(String action) {
  27. this.action = action;
  28. }
  29. }

抽象观察者

  1. /**
  2. * 抽象观察者
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public abstract class Observer {
  6. protected String name;
  7. protected Subject sub;
  8. public Observer(String name, Subject sub) { // 原来是“前台MM”,现改成“抽象通知者”
  9. this.name = name;
  10. this.sub = sub;
  11. }
  12. public abstract void update();
  13. }

看股票的同事

  1. /**
  2. * 看股票的同事
  3. * Created by callmeDevil on 2019/7/27.
  4. */
  5. public class StockObserver extends Observer {
  6. public StockObserver(String name, Subject sub) { // 原来是“前台MM”,现改成“抽象通知者”
  7. super(name, sub);
  8. }
  9. @Override
  10. public void update(){
  11. System.out.println(String.format("%s %s 关闭股票行情,继续工作!", sub.getAction(), name));
  12. }
  13. }

“看NBA的同事”实现与“看股票的同事”类似,此处省略

测试

  1. public class Test {
  2. public static void main(String[] args) {
  3. // 老板
  4. Boss boss = new Boss();
  5. // 看股票的同事
  6. StockObserver observer1 = new StockObserver("哪路托", boss);
  7. // 看NBA的同事
  8. NBAObserver observer2 = new NBAObserver("啥事gay", boss);
  9. boss.attach(observer1);
  10. boss.attach(observer2);
  11. boss.detach(observer1); // 主角光环!斑怎么样都打不过哪路托!所以减去
  12. // 斑复活了!
  13. boss.setAction("我宇智波斑复活了!");
  14. // 发出通知
  15. boss.call();
  16. }
  17. }

测试结果

  1. 我宇智波斑复活了! 啥事gay 关闭NBA 直播,继续工作!

总结

  • 动机是什么?将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象之间的一致性,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
  • 什么时候使用?当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象待改变;一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立的改变和复用。
  • 总的来讲,观察者模式所在的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的改变。
  • 缺点?举个栗子,比如 VS2005,当你点击运行程序时,与运行程序以后,处理弹出一个控制台的程序窗体以外,工具栏发生了变化,工具箱不见了...。仅仅是点击了一个“运行”按钮,就发生这么多变化,而各个变化都涉及到不同的控件,并且没办法让每个控件都去实现一个“Observer”接口,也就是说不可能用接口的方式且实现观察模式。再回过头来看上面的栗子,尽管已经使用了依赖倒转原则,但是“抽象通知者”还是依赖“抽象观察者”,也就是说,万一没有了抽象观察者这样的接口,这通知的功能就完成不了了。另外就是每个具体观察者,他不一定是“更新”的方法要调用,就像刚才说的,我希望的是“工具箱”是隐藏,“自动窗口”是打开,这根本就不是同名的方法,这就是观察者模式不足的地方。在 .NET 中,可以用事件委托较好的解决该缺点,有兴趣的可以查看他人文章,此处不再叙述。

原文链接:http://www.cnblogs.com/call-me-devil/p/11255562.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号