飞道的博客

设计模式(Java)----观察者模式Observer

452人阅读  评论(0)

问题引入:办公时间做与工作无关的事情,在老板到来时,前台负责通知好友进入工作状态.


  
  1. import java.util.ArrayList;
  2. class Secretary{ //前台秘书类
  3. private ArrayList<StockObserver>observers= new ArrayList<StockObserver>();
  4. private String action;
  5. public void Attach(StockObserver observer) {
  6. observers.add(observer);
  7. }
  8. public void Notify() {
  9. for( int i= 0;i<observers.size();i++) {
  10. observers.get(i).Update();
  11. }
  12. }
  13. public String getAction() {
  14. return action;
  15. }
  16. public void setAction(String action) {
  17. this.action=action;
  18. }
  19. }
  20. class StockObserver{ //看股票同事类
  21. private String name;
  22. private Secretary sub;
  23. public StockObserver(String name,Secretary sub) {
  24. this.name=name;
  25. this.sub=sub;
  26. }
  27. public void Update() { //得到前台通知
  28. System.out.println(sub.getAction()+name+ "关闭股票行情,继续工作!");
  29. }
  30. }
  31. public class Main{
  32. public static void main(String[] args){
  33. Secretary tongzhizhe= new Secretary();
  34. StockObserver tongshi1= new StockObserver( "小王",tongzhizhe);
  35. StockObserver tongshi2= new StockObserver( "小李",tongzhizhe);
  36. tongzhizhe.Attach(tongshi1);
  37. tongzhizhe.Attach(tongshi2);
  38. tongzhizhe.setAction( "老板回来了");
  39. tongzhizhe.Notify();
  40. }
  41. }

问题:前台类要增加观察者,观察者类需要前台的状态, 前台类和为股票者类之间互相耦合。如见观察者中还有人想看NBA直播,前台类代码就需要更改。因为前台类和StockObserver都是具体类,依赖具体使得类与类之间产生了紧密联系(耦合),以后假如出现变化,则变一次就要改一次,违背了开放-封闭原则。
解决办法:依赖倒转原则--依赖于抽象,而不是相互依赖,依赖抽象才能应对变化,避免耦合。

 


  
  1. import java.util.ArrayList;
  2. abstract class Subject{ //抽象通知者
  3. abstract void Attach(Observer observer); //添加观察者
  4. abstract void Detach(Observer observer); //删除观察者
  5. abstract void Notify(); //通知观察者
  6. String action;
  7. public String getAction() { //老板状态
  8. return action;
  9. }
  10. public void setAction(String action) {
  11. this.action=action;
  12. }
  13. }
  14. class Boss extends Subject{ //同事列表
  15. private ArrayList<Observer>observers= new ArrayList<Observer>();
  16. @Override
  17. void Attach(Observer observer) {
  18. // TODO Auto-generated method stub
  19. observers.add(observer);
  20. }
  21. @Override
  22. void Detach(Observer observer) {
  23. // TODO Auto-generated method stub
  24. observers.remove(observer);
  25. }
  26. @Override
  27. void Notify() {
  28. // TODO Auto-generated method stub
  29. for( int i= 0;i<observers.size();i++) {
  30. observers.get(i).Update();
  31. }
  32. }
  33. }
  34. class Secretary extends Subject{ //同事列表
  35. private ArrayList<Observer>observers= new ArrayList<Observer>();
  36. @Override
  37. void Attach(Observer observer) {
  38. // TODO Auto-generated method stub
  39. observers.add(observer);
  40. }
  41. @Override
  42. void Detach(Observer observer) {
  43. // TODO Auto-generated method stub
  44. observers.remove(observer);
  45. }
  46. @Override
  47. void Notify() {
  48. // TODO Auto-generated method stub
  49. for( int i= 0;i<observers.size();i++) {
  50. observers.get(i).Update();
  51. }
  52. }
  53. }
  54. abstract class Observer{
  55. protected String name;
  56. protected Subject sub;
  57. public Observer(String name,Subject sub) {
  58. this.name=name;
  59. this.sub=sub;
  60. }
  61. public abstract void Update();
  62. }
  63. class StockObserver extends Observer{
  64. public StockObserver(String name,Subject sub) {
  65. super(name,sub);
  66. }
  67. @Override
  68. public void Update() {
  69. // TODO Auto-generated method stub
  70. System.out.println(sub.getAction()+name+ "关闭股票行情,继续工作!");
  71. }
  72. }
  73. class NBAObserver extends Observer{
  74. public NBAObserver(String name,Subject sub) {
  75. super(name,sub);
  76. }
  77. @Override
  78. public void Update() {
  79. // TODO Auto-generated method stub
  80. System.out.println(sub.getAction()+name+ "关闭NBA直播,继续工作!");
  81. }
  82. }
  83. public class Main{
  84. public static void main(String[] args){
  85. Secretary tongzhizhe= new Secretary();
  86. StockObserver tongzhizhe1= new StockObserver( "小李",tongzhizhe);
  87. NBAObserver tongzhizhe2= new NBAObserver( "小张",tongzhizhe);
  88. tongzhizhe.Attach(tongzhizhe1);
  89. tongzhizhe.Attach(tongzhizhe2);
  90. tongzhizhe.setAction( "老板回来了");
  91. tongzhizhe.Notify();
  92. }
  93. }

结果为:
老板回来了小李关闭股票行情,继续工作!
老板回来了小张关闭NBA直播,继续工作!

观察者模式

Subject类:主题或抽象通知者,一个目标可以被多个观察者观察,目标提供对观察者注册和退订的维护,当目标的状态发生变化时, 目标负责通知所有注册的、有效的观察者。
抽象观察者(Observer)角色:为所有的具体观察者定义一个接口, 在得到主题的通知时更新自己。这个接口叫做更新接口。
具体观察者(ConcreteObserver)角色:具体现察者角色,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。


  
  1. import java.util.ArrayList;
  2. abstract class Subject{
  3. private ArrayList<Observer>observers= new ArrayList<Observer>();
  4. public void attach(Observer observer) {
  5. observers.add(observer);
  6. }
  7. public void detach(Observer onserver) {
  8. observers.remove(observer);
  9. }
  10. void Notify() {
  11. for( int i= 0;i<observers.size();i++) {
  12. observers.get(i).update();
  13. }
  14. }
  15. }
  16. abstract class Observer{
  17. public abstract void update();
  18. }
  19. class ConcreteSubject extends Subject{
  20. private String subjectState;
  21. public String getSubjectState() {
  22. return subjectState;
  23. }
  24. public void setSubjectState(String subjectState) {
  25. this.subjectState = subjectState;
  26. }
  27. }
  28. class ConcreteObserver extends Observer{
  29. private String name;
  30. private String observerState;
  31. private ConcreteSubject subject;
  32. public ConcreteObserver(ConcreteSubject subject,String name) {
  33. this.name=name;
  34. this.subject=subject;
  35. }
  36. @Override
  37. public void update() {
  38. // TODO Auto-generated method stub
  39. observerState=subject.getSubjectState();
  40. System.out.println( "观察者"+name+ "的新状态是"+observerState);
  41. }
  42. }
  43. public class Main{
  44. public static void main(String[] args){
  45. ConcreteSubject s= new ConcreteSubject();
  46. s.attach( new ConcreteObserver(s, "X"));
  47. s.attach( new ConcreteObserver(s, "Y"));
  48. s.attach( new ConcreteObserver(s, "Z"));
  49. s.setSubjectState( "ABC");
  50. s.Notify();
  51. }
  52. }

 结果为:
观察者X的新状态是ABC
观察者Y的新状态是ABC
观察者Z的新状态是ABC

什么时候使用观察者模式?
1、当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
2、当一个抽象模式有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将两者封装在独立的对象中使它们各自独立地改变和复用。

3、观察者模式所做的工作就是解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
这是依赖倒转原则的最佳体现
单向依赖
观察者和目标是单向依赖的,只有观察者依赖于目标,而目标不依赖于观察者。
通知顺序
目标对象的状态变化后通知所有观察者的时候,顺序是不确定的,因此观察者实现的功能,不要依赖于通知顺序,也就是说,多个观察者之间的功能是平行的,相互不应该有先后顺序。
优点:
1、观察者模式实现了观察者和目标之间的抽象耦合。
2、观察者模式实现了动态联动。
3、观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
不足:
1、尽管已经用了依赖倒转原则,但是‘抽象通知者’还是依赖‘抽象观察者’,也就是说,万一没有了抽象观察者这样的接口,通知的功能就完成不了。
2、被观察者会向所有的登记过的观察者发出通知,不管观察者需不需要,每个观察者都会被调用update方法。

Java中的观察者模式
例题:观察者为羊,被观察者为狼。模仿的场景为狼叫羊跑。


  
  1. import java.util.Observable;
  2. import java.util.Observer;
  3. class Wolf extends Observable{
  4. private String name;
  5. Wolf(String name){
  6. this.name=name;
  7. }
  8. public void shout(String state) {
  9. System.out.println( this.getName()+ "shouting");
  10. this.setChanged();
  11. this.notifyObservers(state);
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. }
  20. class Sheep implements Observer{
  21. private String state= "eating";
  22. private String name;
  23. public Sheep(String name) {
  24. this.name=name;
  25. }
  26. public void update(Observable o,Object arg) {
  27. Wolf wolf=(Wolf)o;
  28. System.out.println(wolf.getName()+ "shouting and"+arg+ ""+ this.getName()+ "running");
  29. setState( "runing");
  30. }
  31. public String getState() {
  32. return state;
  33. }
  34. public void setState(String state) {
  35. this.state = state;
  36. }
  37. public String getName() {
  38. return name;
  39. }
  40. public void setName(String name) {
  41. this.name = name;
  42. }
  43. }
  44. public class Main{
  45. public static void main(String[] args){
  46. Wolf wolf= new Wolf( "wolf1");
  47. Sheep sheep1= new Sheep( "sheep1");
  48. Sheep sheep2= new Sheep( "sheep2");
  49. Sheep sheep3= new Sheep( "sheep3");
  50. wolf.addObserver(sheep1);
  51. wolf.addObserver(sheep2);
  52. String wolfstat= "hungry";
  53. wolf.shout(wolfstat);
  54. }
  55. }

结果为:
wolf1shouting
wolf1shouting andhungrysheep2running
wolf1shouting andhungrysheep1running
 


转载:https://blog.csdn.net/jiahuier/article/details/106411679
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场