觀察者模式(Java 版)

注:源碼及見解參見慕課網

第一節

1.官方定義:

定義對象間的一種一對多的依賴關系。當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新

2.觀察者模式的結構:

Subject Observer
+Attach(o:Observer) +Update( )
+Detach(o:Observer)
+Notify( )

3.標準模板

Subject.java

import java.util.ArrayList;
import java.util.List;

public class Subject {
     //保護注冊的觀察者對象
     private List observers = new ArrayList();
    
     public void attath(Observer observer){
               observers.add(observer);
     }
     
     public void detach(Observer observer){
               observers.remove(observer);
     }
    
     protected void notifyObservers(){
               for(Observer observer:observers){
                        observer.update(this);
               }
     }     
}

Observer.java

public interface Observer {
public void update(Subject subject);
} 

ConcreteSubject.java

public class ConcreteSubject extends Subject {
  /*目標對象的狀態*/
  private String subjectState;
  public String getSubjectState() {
    return subjectState;
  }

  /*通知觀察者*/
  public void setSubjectState(String subjectState) {
    this.subjectState = subjectState;
    this.notifyObservers();
  }
}

ConcreteObserver.java

public class ConcreteObserver implements Observer { 
/*觀察者的狀態*/
  private String observerState;

  public void update(Subject subject) {
    observerState = ((ConcreteSubject)subject).getSubjectState();
  }
}

4.實例

weather.java

import java.util.ArrayList;
import java.util.List;
public class Weather {
     //創建觀察者列表
     private List people = new ArrayList();
     //添加觀察者
     public void attath(People people){
               this.people.add(people);
     }  
     //刪除觀察者
     public void detach(People people){
               this.people.remove(people);
     }
     //通知觀察者更新
     protected void updata(){
               for(Peoplehuman:people){
                        human.updata(this);
               }
     }
}

TodayWeather.java

public class ConcreteObserver implements Observer {
  //觀察者的狀態
  private String observerState;

  public void update(Subject subject) {
    observerState = ((ConcreteSubject)subject).getSubjectState();
  }
}

People.java

public interface People {
  //創建更新的接口
  public void updata(Weather weather);
}

ConcretePeople.java

public classConcretePeople implements People{
  private String infromation;  
  private String name;
  private String talk;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getTalk() {
    return talk;
  }
  public void setTalk(String talk) {
    this.talk = talk;
  }
  @Override
  public void updata(Weather weather) {
    infromation = ((TodayWeather)weather).getWeatherContext();
    System.out.println(name+"說:今天"+infromation+talk);
  }
}

Test.java

public class Test {
  public static void main(String[] args) {
    ConcretePeople man = new ConcretePeople();
    man.setName("小強");
    man.setTalk("以該出去踢球");
   
    ConcretePeople woman = new ConcretePeople();
    woman.setName("小紅");
    woman.setTalk("應該去逛街");
   
    TodayWeather todayWeather = new TodayWeather();
    todayWeather.setWeatherContext("天氣晴朗,藍天白云,沒有霧霾?。?);
   
    man.updata(todayWeather);
    woman.updata(todayWeather);
  }
}

輸出結果:
小強說:今天天氣晴朗,藍天白云,沒有霧霾??!以該出去踢球
小紅說:今天天氣晴朗,藍天白云,沒有霧霾??!應該去逛街


第二節

上一節里,我書寫了觀察者模式的模板和例子,
這一次我要再次深入的介紹觀察者模式的兩種方式和java自己封裝好的觀察者結構。

1.實現的兩種方式:

推模型和拉模型

推模型:目標對象主動向觀察者推送目標的詳細信息,推送的信息通常是目標對象的全部或部分數據。
拉模型:目標對象在通知觀察者的時候,只傳遞少量信息。
如果觀察者需要更具體的信息,由觀察者主動到目標對象中獲取,相當于是觀察者從目標對象中拉數據。
一般這種模型的實現中,會把目標對象自身通過update方法傳遞給觀察者。
對于拉模型,上次一文中介紹的模板和例子均是采用的拉模型。下面我為大家修改上次的例子變成推模型。

Weather.java

import java.util.ArrayList;
import java.util.List;
public class Weather {
     //創建觀察者列表
     private List people = new ArrayList();
     //添加觀察者
     public void attath(People people){
               this.people.add(people);
     }
     //刪除觀察者
     public void detach(People people){
               this.people.remove(people);
     }
     //通知觀察者更新
     protected void updata(String content){
               for(Peoplehuman:people){
                        human.updata(content);
               }
     }
}

TodayWeather.java

public class TodayWeather extends Weather{
  //今日天氣
  private String weatherContext;
  public String getWeatherContext**() {
    return weatherContext;
  }
  public void setWeatherContext(String weatherContext) {
    this.weatherContext = weatherContext;
    this.updata(weatherContext);
  }

People.java

public interface People { 
  //創建更新的接口
  public void updata(String content);
}

ConcreteWeather.java

public class ConcretePeople implements People{
  private String infromation;  
  private String name;
  private String talk;
  public String getName() {
    return name;
  }
  public void setName**(String name) {
    this.name = name;
  }
  public String getTalk() {
    return talk;
  }
  public void setTalk(String talk) {
    this.talk = talk;
  }
  @Override
  public void updata(String content) {
    infromation = content;
    System.out.println(name+"說:今天"+infromation+talk);
  }
}

Test.java

public class Test {
  public static void main(String[] args) {
    ConcretePeople man = new ConcretePeople();
    man.setName("小強");
    man.setTalk("以該出去踢球");
    ConcretePeople woman = new ConcretePeople();
    woman.setName("小紅");
    woman.setTalk("應該去逛街");
    TodayWeather todayWeather = new TodayWeather();
    todayWeather.setWeatherContext("天氣晴朗,藍天白云,沒有霧霾??!");
    man.updata(todayWeather.getWeatherContext());
    woman.updata(todayWeather.getWeatherContext());
  }  
}

輸出結果:
小強說:今天天氣晴朗,藍天白云,沒有霧霾??!以該出去踢球
小紅說:今天天氣晴朗,藍天白云,沒有霧霾!!應該去逛街

2.推拉模型的比較

Weather.java?

import java.util.Observable;
public class Weather extends Observable{
  private String WeatherContent;
  public String getWeatherContent() {
    return WeatherContent;
  }
  public void setWeatherContent(String weatherContent) {
    WeatherContent = weatherContent;
    //下面這句話在調用java里的Observer時必不可少
    this.setChanged();
    //這是拉模型沒有參數
    this.notifyObservers();
    //這是推模型帶參數
    this.notifyObservers(weatherContent);
  }
}

?People.java

import java.util.Observable;
public class Weather extends Observable{
   private String WeatherContent;
   public String getWeatherContent() {
     return WeatherContent;
   }
   public void setWeatherContent(String weatherContent) {
     WeatherContent = weatherContent;
     //下面這句話在調用java里的Observer時必不可少
     this.setChanged();
     //這是拉模型沒有參數
     this.notifyObservers();
     //這是推模型帶參數
     this.notifyObservers(weatherContent);
  }
}

?Test.java

public class Test {
public static void main(String[] args) {
  Weather weather = new Weather();
  weather.setWeatherContent("今天天氣晴朗,藍天白云??!");
  People man = new People();
  man.setName("小明");
  man.setTalk("我去踢球");
  People woman = new People();
  woman.setName("小紅");
  woman.setTalk("我要逛街");
  man.update(weather, weather.getWeatherContent());
  woman.update(weather, weather.getWeatherContent());
  }
}

輸出結果:
小明說:今天天氣晴朗,藍天白云!!,我去踢球推模式
小明說:今天天氣晴朗,藍天白云!!,我去踢球拉模式
小紅說:今天天氣晴朗,藍天白云??!,我要逛街推模式
小紅說:今天天氣晴朗,藍天白云??!,我要逛街拉模式


第三節

1.區別對待觀察者場景問題:

最后一個問題,就是判斷性的添加觀察者。實現方法很簡單,將subject這個類中的notifyChange()這個方法讓其不去實現,使其在他的派生類中實現,(這樣我們不妨把subject這個類作為抽象類,然后將notufyChange()這個方法作為抽象方法讓其在子類中實現方法)然后就是在concretesubject()中在notifyChange()來判斷那個對象可以做更新。(注:這里的方法名均為第一篇文章中模板的名字,和下面的例子不同)。

Weather.java

import java.util.ArrayList;
import java.util.List;
public abstract class Weather {
  public List People humans = new ArrayListPeople();
  public void attach(People people){
    humans.add(people);
  }
  public void detach(People people){
    humans.remove(people);
  }
  public abstract void notifyWeather();
}

Today.java

public class Today extends Weather{
  private String weatherContent;
  public void notifyWeather() {
    for(People human:humans){
      if(weatherContent.equals("下雨")){
        if(human.getPeopleName().equals("小紅")){
          human.updata(this);
        }
      }
     if(weatherContent.equals("下雪")){
       if(human.getPeopleName().equals("小明")){
         human.updata(this);
       }
     }
    }
  }
  public String getWeatherContent() {
     return weatherContent;
  }
  public void setWeatherContent(String weatherContent) {
    this.weatherContent = weatherContent;
    this.notifyWeather();
  }
}

People.java

public interface People {
  public void updata(Weather weather);
  public void setPeopleName(String name);
  public String getPeopleName();
}

Human.java

public class Human *implements People{
  private String name;
  public String getTalk() {
    return talk;
  }
  public void setTalk(String talk) {
    this.talk = talk;
  }
  public String getWeatherContent() {
    return weatherContent;
  }
  private String talk;
  private String weatherContent;
  @Override
  public void updata(Weather weather) {
    System.out.println(name+"說:"+((Today)weather).getWeatherContent()+talk);
  }
  @Override
  public void setPeopleName(String name) {
    this.name = name;
  }
  @Override
  public String getPeopleName**() {
    return this.name;
  }
}

Test.java

public class Test {
  public static void main(String[] args) {
    Today today = new Today();
    Human man = new Human();
    man.setPeopleName("小明");
    man.setTalk("我要看雪");

    Human woman = new Human();
    woman.setPeopleName("小紅");
    woman.setTalk("下雨了不去了");

    today.attach(man);
    today.attach(woman);
    today.setWeatherContent("下雪");
  }
}

輸出結果:
小明說:下雪我要看雪


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容