模式说明

当一个对象变化时,所有与他有关联关系的对象都将因为这个变化而变化,将前者称为目标对象,后者称为观察者对象。例如以人行道上的红绿灯为目标对象,行人和车辆为观察者对象。当红绿灯从红灯变为绿灯时,行人因为这个变化而从等待转变为过马路,而汽车则从通过转变为等待,这些观察者都对目标的变化做出了反映。此类场景可以用观察者模式实现。

本示例以人民币汇率为目标对象,进口公司和出口公司作为观察者对象。演示目标对象变化时,如何通知所有观察者做出其响应的动作。

结构

抽象目标类
观察者需要观察的对象,类内实现添加和删除观察者的普通方法,定义一个通知所有观察者的抽象方法。
具体目标类
继承抽象目标类,实现抽象方法。
抽象观察者类
持有一个name属性,并有对应的getter/setter。定义了一个响应目标对象变化的抽象方法action,被目标类通知时执行。
具体观察者类
继承抽象观察者类,实现抽象方法action

代码演示

  1. package com.yukiyama.pattern.behavior;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /**
  5. * 观察者模式
  6. */
  7. public class ObserverDemo {
  8. public static void main(String[] args) {
  9. // 声明一个具体目标对象,人民币汇率
  10. Rate rate = new RMBRate();
  11. // 声明两个不同的观察者对象,进口公司和出口公司
  12. Company watcher1 = new ImportCompany();
  13. Company watcher2 = new ExportCompany();
  14. // 将观察者都加入到目标对象中,以便目标能够在自身产生变化时通知所有观察者
  15. rate.add(watcher1);
  16. rate.add(watcher2);
  17. // 当汇率升高3.5%时,进出口公司分别对这个变化做出应对
  18. rate.change(0.035);
  19. // 当汇率下降6.8%时,进出口公司分别对这个变化做出应对
  20. rate.change(-0.068);
  21. }
  22. }
  23. /**
  24. * 抽象目标类(被观察事物)
  25. * 持有一个观察者类实例的集合,实现两个非抽象方法,add方法用来添加观察者
  26. * 实例,remove方法用来删除观察者实例。另有一个抽象方法change,传入变化。
  27. */
  28. abstract class Rate{
  29. protected List<Company> companies = new ArrayList<>();
  30. public void add(Company company) {
  31. companies.add(company);
  32. }
  33. public void remove(Company company) {
  34. companies.remove(company);
  35. }
  36. public abstract void change(double changedRate);
  37. }
  38. /**
  39. * 具体目标类
  40. * 继承抽象目标类,实现抽象方法change,在方法内遍历其持有的所有观察者,
  41. * 传入变化,执行观察者的action方法。
  42. */
  43. class RMBRate extends Rate{
  44. @Override
  45. public void change(double changedRate) {
  46. System.out.printf("人民币汇率变动%.1f%%\n", changedRate*100);
  47. for(Company company : this.companies) {
  48. company.action(changedRate);
  49. }
  50. }
  51. }
  52. /**
  53. * 抽象观察者类
  54. * 持有一个name属性,并有对应的getter/setter。定义了一个action抽象方法。
  55. * 下例以公司为抽象观察者类。
  56. */
  57. abstract class Company{
  58. private String name;
  59. public String getName() {
  60. return name;
  61. }
  62. public void setName(String name) {
  63. this.name = name;
  64. }
  65. public abstract void action(double changedRate);
  66. }
  67. /**
  68. * 具体观察者类
  69. * 通过无参构造器初始化name。实现抽象观察者类中的抽象方法action。
  70. * 下例是进口公司观察者,action内实现当人民币汇率降低时减少相应比例
  71. * 的进口量,升高时增加相应比例的进口量。
  72. */
  73. class ImportCompany extends Company{
  74. public ImportCompany() {
  75. this.setName("进口公司");
  76. }
  77. @Override
  78. public void action(double changedRate) {
  79. System.out.printf("%s动作:\n", this.getName());
  80. if(changedRate < 0) {
  81. System.out.printf("人民币汇率下降了%.1f%%,减少%.1f%%进口量。\n",
  82. -changedRate*100, -changedRate*100);
  83. } else {
  84. System.out.printf("人民币汇率上升了%.1f%%,增加%.1f%%进口量。\n",
  85. changedRate*100, changedRate*100);
  86. }
  87. }
  88. }
  89. /**
  90. * 具体观察者类
  91. * 下例是出口公司观察者,action内实现当人民币汇率降低时增加相应比例
  92. * 的进口量,升高时减少相应比例的进口量。
  93. */
  94. class ExportCompany extends Company{
  95. public ExportCompany() {
  96. this.setName("出口公司");
  97. }
  98. @Override
  99. public void action(double changedRate) {
  100. System.out.printf("%s动作:\n", this.getName());
  101. if(changedRate < 0) {
  102. System.out.printf("人民币汇率下降了%.1f%%,增加%.1f%%出口量。\n",
  103. -changedRate*100, -changedRate*100);
  104. } else {
  105. System.out.printf("人民币汇率上升了%.1f%%,下降%.1f%%出口量。\n",
  106. changedRate*100, changedRate*100);
  107. }
  108. }
  109. }