Java基础知识之设计模式--观察者模式

Java设计模式--观察者模式

声明:本文根据慕课网GerryZhang老师的精品课程整理来的:慕课网

 什么是设计模式(Design Pattern)?

  设计模式是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结。

观察者模式的定义?

  定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知,并被自动更新。

观察者模式的分类?

  1.推模型:目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或部分数据,相当于广播通信

  2.拉模型:目标对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据。一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者。

Java中提供的观察者实现与自己实现的对比:

  1.不需要再定义观察者和目标的接口了,JDK帮忙定义了

  2.具体的目标实现里面不需要再维护观察者的注册信息了,这个在Java中的Observable类里面已经帮忙实现了。

  3.触发通知的方式有一些变化,要先调用setChanged方法,这个是Java为了帮助实现更精确的触发控制而提供的功能。

  4.具体观察者的实现里面,update方法其实能同时支持推模型和拉模型,这个是Java在定义的时候,就已经考虑进去了。

观察者模式的优点和缺点:

  优点:

    1.观察者模式实现了观察者和目标之间的抽象耦合。

    2.观察者模式实现了动态联动。

    3.观察者模式支持广播通信。

  缺点:

    可能会引起无谓的操作

在什么情况下使用观察者模式:

  1.当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化。

  2.如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变。

  3.当一个对象必须通知其他的对象,但你又希望这个对象和其他被通知的对象是松散耦合的。

推模型示例:

  1.创建观察者接口和目标对象

 /**
  * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时被通知的对象
  * @author Administrator
  *
  */
 public interface Observer {
     /**
      * 更新的接口
      * @Description: TODO
      * @param subject
      * @returnType: void
      */
     public void update(WeatherSubject subject);
 }
/**
  * 目标对象,它知道观察它的观察者,并提供注册(添加)和删除观察者的接口。
  * @author Administrator
  *
  */
 public class WeatherSubject {
     // 用来保存注册的观察者对象
     List<Observer> observers = new ArrayList<Observer>();
 
     /**
      * 把订阅的人添加到订阅者列表中
      */
     public void attach(Observer observer) {
         observers.add(observer);
     }
 
     /**
      * 从集合中删除观察者
      */
     public void detach(Observer observer) {
         if (observers.contains(observer)) {
             observers.remove(observer);
         }
     }
 
     /**
      * 通知所有注册的观察者对象
      */
     protected void notifyObservers() {
         for (Observer observer : observers) {
             observer.update(this);
         }
     }
 }

  2.分别创建具体的目标对象和具体的观察者对象

 /**
   * 具体的目标对象,负责把有关状态存入到相应的观察者对象中
   * @author Administrator
   *
   */
  public class ConcreteWeatherSubject extends WeatherSubject {
      //获取天气的内容信息
      private String weatherContent;
  
      /**
       * @return the weatherContent
       */
      public String getWeatherContent() {
          return weatherContent;
      }
  
      /**
       * @param weatherContent the weatherContent to set
       */
      public void setWeatherContent(String weatherContent) {
          this.weatherContent = weatherContent;
          //内容有了,说明天气更细了,通知所有的订阅人
          this.notifyObservers();
      }  
  }
 /**
  * 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
   * @author Administrator
   *
  */
 public class ConcreteObserver implements Observer {
      //观察者的名字,是谁收到了这个信息
      private String observerName;
      
     //天气内容的情况,这个消息从目标处获取
     private String weatherContent;
     
     //提醒的内容,根据不同的人提醒不同的信息
     private String remindThing;
     
     /**
      * 获取目标类的状态同步到观察者的状态中
      */
     @Override
     public void update(WeatherSubject subject) {
         weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent();
         System.out.println(observerName+"收到了"+weatherContent+","+remindThing);
     }
 
     /**
      * @return the observerName
      */
     public String getObserverName() {
         return observerName;
     }
 
     /**
      * @param observerName the observerName to set
      */
     public void setObserverName(String observerName) {
         this.observerName = observerName;
     }
 
     /**
      * @return the weatherContent
      */
     public String getWeatherContent() {
         return weatherContent;
     }
 
     /**
      * @param weatherContent the weatherContent to set
      */
     public void setWeatherContent(String weatherContent) {
         this.weatherContent = weatherContent;
     }
 
     /**
      * @return the remindThing
      */
     public String getRemindThing() {
         return remindThing;
     }
 
     /**
      * @param remindThing the remindThing to set
      */
     public void setRemindThing(String remindThing) {
         this.remindThing = remindThing;
     } 
}

  3.创建测试类进行测试

  程序运行逻辑(准备阶段):

    1.创建目标对象

    2.创建观察者对象

    3.向目标对象注册观察者对象

  程序性运行逻辑(运行阶段):

    1.改变目标对象的状态

    2.目标对象通知所有观察者对象运行相应的处理

    3.观察者对象回调目标对象,获取相应的数据

 public class Test {
  
      public static void main(String[] args) {
          //1.创建一个目标
          ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
          
          //2.创建一个观察者
          ConcreteObserver girlObserver = new ConcreteObserver();
          girlObserver.setObserverName("黄明的女朋友");
         girlObserver.setRemindThing("天气很好,适合约会");
         
         ConcreteObserver mumObserver = new ConcreteObserver();
         mumObserver.setObserverName("黄明的老妈");
         mumObserver.setRemindThing("天气很好,适合购物");
         
         //3.注册观察者
         subject.attach(girlObserver);;
         subject.attach(mumObserver);
         
         //4.目标发布天气
         subject.setWeatherContent("明天天气晴朗,气温28度");
     }
 
 }

拉模型示例:

  1.创建观察者接口和目标对象

 /**
   * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时被通知的对象
   * @author Administrator
   *
   */
  public interface Observer {
      /**
       * 更新的接口
       * @Description: TODO
      * @param subject
      * @returnType: void
      */
     public void update(String content);
 }
 /**
   * 目标对象,它知道观察它的观察者,并提供注册(添加)和删除观察者的接口。
   * @author Administrator
   *
   */
  public class WeatherSubject {
      // 用来保存注册的观察者对象
      List<Observer> observers = new ArrayList<Observer>();
  
     /**
      * 把订阅的人添加到订阅者列表中
      */
     public void attach(Observer observer) {
         observers.add(observer);
     }
 
     /**
      * 从集合中删除观察者
      */
     public void detach(Observer observer) {
         if (observers.contains(observer)) {
             observers.remove(observer);
         }
     }
 
     /**
      * 通知所有注册的观察者对象
      */
     protected void notifyObservers(String content) {
         for (Observer observer : observers) {
             observer.update(content);
         }
     }
 } 

  2.分别创建具体的目标对象和具体的观察者对象

 /**
   * 具体的目标对象,负责把有关状态存入到相应的观察者对象中
   * @author Administrator
   *
   */
  public class ConcreteWeatherSubject extends WeatherSubject {
      //获取天气的内容信息
      private String weatherContent;
  
     /**
      * @return the weatherContent
      */
     public String getWeatherContent() {
         return weatherContent;
     }
 
     /**
      * @param weatherContent the weatherContent to set
      */
     public void setWeatherContent(String weatherContent) {
         this.weatherContent = weatherContent;
         //内容有了,说明天气更细了,通知所有的订阅人
         this.notifyObservers(weatherContent);
     } 
 }
 /**
   * 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
   * @author Administrator
   *
   */
  public class ConcreteObserver implements Observer {
      //观察者的名字,是谁收到了这个信息
      private String observerName;
      
     //天气内容的情况,这个消息从目标处获取
     private String weatherContent;
     
     //提醒的内容,根据不同的人提醒不同的信息
     private String remindThing;
     
     /**
      * 获取目标类的状态同步到观察者的状态中
      */
     @Override
     public void update(String content) {
         weatherContent = content;
         System.out.println(observerName+"收到了"+weatherContent+","+remindThing);
     }
 
     /**
      * @return the observerName
      */
     public String getObserverName() {
         return observerName;
     }
 
     /**
      * @param observerName the observerName to set
      */
     public void setObserverName(String observerName) {
         this.observerName = observerName;
     }
 
     /**
      * @return the weatherContent
      */
     public String getWeatherContent() {
         return weatherContent;
     }
 
     /**
      * @param weatherContent the weatherContent to set
      */
     public void setWeatherContent(String weatherContent) {
         this.weatherContent = weatherContent;
     }
 
     /**
      * @return the remindThing
      */
     public String getRemindThing() {
         return remindThing;
     }
 
     /**
      * @param remindThing the remindThing to set
      */
     public void setRemindThing(String remindThing) {
         this.remindThing = remindThing;
     }   
 }

  3.创建测试类进行测试

 public class Test {
      public static void main(String[] args) {
          // 1.创建一个目标
          ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
  
          // 2.创建一个观察者
          ConcreteObserver girlObserver = new ConcreteObserver();
          girlObserver.setObserverName("黄明的女朋友");
          girlObserver.setRemindThing("天气很好,适合约会");
 
         ConcreteObserver mumObserver = new ConcreteObserver();
         mumObserver.setObserverName("黄明的老妈");
         mumObserver.setRemindThing("天气很好,适合购物");
 
         // 3.注册观察者
         subject.attach(girlObserver);
         ;
         subject.attach(mumObserver);
 
         // 4.目标发布天气
         subject.setWeatherContent("明天天气晴朗,气温28度");
     }
 }

使用Java提供的观察者实现进行实例测试:

  1.创建目标的具体实现类,继承于Java提供的Observable类

 /**
   * 天气目标的具体实现类
   * @author Administrator
   *
   */
  public class ConcreteWeatherSubject extends Observable {
      //天气情况的内容
      private String content;
  
     public String getContent() {
         return content;
     }
     
     public void setContent(String content) {
         this.content = content;
         //天气情况有了,就要通知所有的观察者
         //注意在通知之前,在用Java中的Observer模式的时候,下面这句话不可少
         this.setChanged();
         //然后主动通知,这里用推的模式实现
         this.notifyObservers(content);
         //如果是拉的模式实现,使用不带参数的
         //this.notifyObservers();
     }
 }

  2.创建具体的观察者对象,实现Java提供的Observer接口

 /**
   * 具体的观察者对象
   * @author Administrator
   *
   */
  public class ConcreteObserver implements Observer {
  
      //观察者名称的变量
      private String observerName;
     @Override
     public void update(Observable o, Object arg) {
         //第一种是推的方式
         System.out.println(observerName+"收到了消息,目标推送过来的是:"+arg);
         //第二种是拉的方式
         System.out.println(observerName+"收到了消息,主动到目标对象中去拉,拉的内容是"
                 +((ConcreteWeatherSubject)o).getContent());
     }
     public String getObserverName() {
         return observerName;
     }
     public void setObserverName(String observerName) {
         this.observerName = observerName;
     }
 }

  3.测试类

 /**
   * 测试类
   * @author Administrator
   *
   */
  public class Test {
      public static void main(String[] args) {
          //创建天气作为一个目标,也可以说是被观察者
          ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
         //创建黄明的女朋友作为观察者
         ConcreteObserver girlObserver = new ConcreteObserver();
         girlObserver.setObserverName("黄明的女朋友");
         //创建黄明的老妈作为观察者
         ConcreteObserver mumObserver = new ConcreteObserver();
         mumObserver.setObserverName("黄明的老妈");
         
         //注册观察者
         subject.addObserver(mumObserver);
         subject.addObserver(girlObserver);
         
         //目标更新天气情况
         subject.setContent("天气晴,气温28度");
     }
 }
原文地址:https://www.cnblogs.com/wk-missQ1/p/12319432.html