国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

觀察者模式組圖(Observer Pattern)

2019-11-18 12:15:59
字體:
來源:轉載
供稿:網友

  描述:
  
  在設計一組依靠的對象與它們所依靠的對象之間一致(同步)的交流模型時,觀察者模式(Observer Pattern)很有用。它可以使依靠對象的狀態與它們所依靠的對象的狀態保持同步。這組依靠的對象指的是觀察者(Observer),它們所依靠的對象稱為主題(Subject)。為了實現觀察者(Observer)的狀態與主題(Subject)保持同步,觀察者模式(Observer Pattern)
  
  推薦采用發布者--訂閱者(publisher--subscriber)模型,以使這組觀察者(Observer)和主題(Subject)對象之間有清楚的界限。
  
  典型的觀察者(Observer)是一個依靠于或者關注于主題對象的狀態的對象。一個主題可以有一個或者多個觀察者。這些觀察者在主體的狀態發生變化時,需要得到通知。
  
  由于給定主體的觀察者鏈表需要動態的變化,因此一個主題不能維護一個靜態的觀察者鏈表。因此關注于主題狀態的任何對象都需要明確地注冊自己為主體的一個觀察者。主題狀態發生的變化,都需要通知所有的以注冊的觀察者。從主題接到通知以后,每一個觀察者查詢主題,使自己的狀態與主題的同步。因此一個主題扮演著發布者的角色,發布信息到所有的以訂閱的觀察者。
  
  換句話說,主題和它的觀察者之間包含了一對多的關系。當主題的實例的狀態發生變化時,所有的依靠于它的觀察者都會得到通知并更新自己。每一個觀察者對象需要向主題注冊,當主題的狀態發生變化的時候得到通知。一個觀察者可以注冊或者訂閱多個主題。當觀察者不希望再得到通知時,它可以向主題進行注銷。
  
  為了實現這種機制:
  
  (1)  主題需要為注冊和注銷通知提供一個接口。
  
  (2)  下面的兩點也需要滿足:
  
  A、  拉模型(In the pull model)--主題需要提供一個接口,可以使觀察者查詢主題獲得需要的狀態信息來更新自己的狀態。
  
  B、  推模型(In the push model)--主題發送觀察者可能關注的狀態信息。
  
  (3)  觀察者需要提供一個可以從主題接受通知的接口。
  
  類圖(圖33.1)描述了為滿足于以上需求,不同類的結構和它們之間的關聯關系。
  
 觀察者模式組圖(Observer Pattern)(圖一)
  Figure 33.1: Generic Class Association When the Observer Pattern Is Applied
  

  從這個類圖可以看到:
  
  (1)  所有的主題需要提供一個類似于Observable接口的實現。
  
  (2)  所有的觀察者需要提供一個類似于Observer接口的實現。
  
  在應用觀察者模式時,有幾種變體。這就會產生不同類型的主題--觀察者模式,例如,觀察者僅關注主體特定類型的變化等。
  
  增加新的觀察者:
  
  應用觀察者模式以后,在不影響主題類的情況下,可以動態的加入不同的觀察者。同樣,主題的狀態變化邏輯改變時,觀察者也不會受到影響。
  
  例子:
  
  為了治理一個賣廠多個分類產品,讓我們建立一個銷售報表系統。這個系統有以下特征:
  
  (1)  用戶可以選擇一個他們感愛好的分類
  
  (2)  在選擇了一個分類以后,需要顯示下面的兩種類型的報表。
  
  A、  月度報表(Monthly report)--所選分類當月的所有交易清單。
  
  B、  年度累積額(YTD sales chart)--以月為單位顯示選擇分類的年度累積額圖。
  
  (3)  當一個不同的分類被選擇時,兩種報表的數據會被刷新,顯示當前所選分類的報表。
  
  為了實現以上期望的功能,我們很輕易的看到兩個報表對象依靠于持有用戶選擇分類的對象。應用觀察者模式于此場景,我們可以設計一個介于持有用戶選擇分類的對象和兩個報表對象之間一個一致(同步)的交流模型。
  
  讓我們定義三個類,它們的功能如表33.1所描述:
  
  Table 33.1: Subject-Observer Classes
  public interface Observable {
  public void notifyObservers();
  public void register(Observer obs);
  public void unRegister(Observer obs);
  }
  
  ReportManager類(Listing33.1)提供了聲明在Observable接口中方法的實現。兩個依靠于ReportManager的報表對象使用這些方法注冊它們自己為觀察者。ReportManager把這些注冊的觀察者保存到observersList矢量(vector)中。當前選擇的分類構成了ReportManager對象的狀態,它以實例變量的形式保存在變量department中。當為department設置一個新的值時(也就是ReportManager對象的狀態改變),notifyObservers方法被調用。作為notifyObservers方法的一部分,ReportManager調用注冊為觀察者的refreshData(Observable)方法。
  Listing 33.1: ReportManager Class
  
  public class ReportManager extends JFrame
  implements Observable {
  …
  …
  PRivate Vector observersList;
  private String department;
  public ReportManager() throws Exception {
  …
  …
  observersList = new Vector();
  …
  …
  }
  public void register(Observer obs) {
  //Add to the list of Observers
  observersList.addElement(obs);
  }
  public void unRegister(Observer obs) {
  //remove from the list of Observers
  }
  public void notifyObservers() {
  //Send notify to all Observers
  for (int i = 0; i < observersList.size(); i++) {
  Observer observer =
  (Observer) observersList.elementAt(i);
  observer.refreshData(this);
  }
  }
  public String getDepartment() {
  return department;
  }
  public void setDepartment(String dept) {
  department = dept;
  }
  class ButtonHandler implements ActionListener {
  ReportManager subject;
  public void actionPerformed(ActionEvent e) {
  if (e.getActionCommand().equals(ReportManager.EXIT)) {
  System.exit(1);
  }
  if (e.getActionCommand().equals(ReportManager.SET_OK)) {
  String dept = (String)
  cmbDepartmentList.getSelectedItem();
  //change in state
  subject.setDepartment(dept);
  subject.notifyObservers();
  }
  }
  public ButtonHandler() {
  }
  public ButtonHandler(ReportManager manager) {
  subject = manager;
  }
  }
  }//end of class
  
  除了提供Observable接口方法的實現,ReportManager還顯示了必要的用戶接口,答應用戶選擇一個特定的、關注的分類。
  
  讓我們定義接口Observer的兩個實現:MonthlyReport和YTDChart類
  
  public interface Observer {
  public void refreshData(Observable subject);
  }
  
 觀察者模式組圖(Observer Pattern)(圖二)
  Figure 33.2: Observer Class Hierarchy
  

  Listing 33.2: MonthlyReport Class as an Observer
  
  public class MonthlyReport extends JFrame implements Observer {
  …
  …
  private ReportManager objReportManager;
  public MonthlyReport(ReportManager inp_objReportManager)
  throws Exception {
  super("Observer Pattern -- Example");
  objReportManager = inp_objReportManager;
  //Create controls
  …
  …
  //Create Labels
  …
  …
  objReportManager.register(this);
  }
  public void refreshData(Observable subject) {
  if (subject == objReportManager) {
  //get subject's state
  String department = objReportManager.getDepartment();
  lblTransactions.setText(
  "Current Month Transactions - " +
  department);
  Vector trnList =
  getCurrentMonthTransactions(department);
  String content = "";
  for (int i = 0; i < trnList.size(); i++) {
  content = content +
  trnList.elementAt(i).toString() + "/n";
  }
  taTransactions.setText(content);
  }
  }
  private Vector getCurrentMonthTransactions(String department
  ) {
  Vector v = new Vector();
  FileUtil futil = new FileUtil();
  Vector allRows = futil.fileToVector("Transactions.date");
  //current month
  Calendar cal = Calendar.getInstance();
  cal.setTime(new Date());
  int month = cal.get(Calendar.MONTH) + 1;
  String searchStr = department + "," + month + ",";
  int j = 1;
  for (int i = 0; i < allRows.size(); i++) {
  String str = (String) allRows.elementAt(i);
  if (str.indexOf(searchStr) > ?1) {
  StringTokenizer st =
  new StringTokenizer(str, ",");
  st.nextToken();//bypass the department
  str = " " + j + ". " + st.nextToken() + "/" +
  st.nextToken() + "~~~" +
  st.nextToken() + "Items" + "~~~" +
  st.nextToken() + " Dollars";
  j++;
  v.addElement(str);
  }
  }
  return v;
  }
  }//end of class
  
  ReportManager利用這個接口通知它的所有觀察者。
  
  主題--觀察者的關聯(Subject--Observer Association)
  
  通常,一個客戶首先需要創建一個主題(ReportManager)實例,當一個觀察者(例如:MonthlyReport,YTDChart)對象被創建。客戶把主題ReportManager實例的引用傳遞給觀察者的構造函數,觀察者將自身注冊到當前主題實例上。
  
  //Client Code
  public class SupervisorView {
  …
  …
  public static void main(String[] args) throws Exception {
  //Create the Subject
  ReportManager objSubject = new ReportManager();
  //Create Observers
  new MonthlyReport(objSubject);
  new YTDChart(objSubject);
  }
  }//end of class
  
  類之間的關聯描述如下:
  
 觀察者模式組圖(Observer Pattern)(圖三)
  Figure 33.3: Example application--Class Association
  

  邏輯流程:
  
  (1)  使用ReportManager用戶接口,當用戶選擇一個特定的分類并且點擊OK按鈕時,ReportManager的內部狀態被被改變(例如,ReportManager實例變量department的值發生改變)。
  
  (2)  新的狀態一旦被設置,ReportManager調用兩個注冊的觀察者MonthlyReport和YTDChart的refreshData(Observable)方法。
  
  (3)  作為refreshData方法的一部分,兩個report對象需要:
  
  A、  檢查以確保調用refreshData方法的主題和觀察者這冊的主題是同一個主題。這就避免了觀察者響應不必要的調用。
  
  B、  使用getDepartment方法查詢ReportManager的當前狀態。
  
  C、  從數據文件中提取響應的數據顯示。
  
 觀察者模式組圖(Observer Pattern)(圖四)
  Figure 33.4: MonthlyReport View

  
  當ReportManager的狀態變化邏輯實現需要改變時,任何觀察者不受影響。同樣,當一個新的觀察者被加入時,ReportManager類不需要任何變化。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鄂托克旗| 吉林市| 建瓯市| 新宾| 个旧市| 曲麻莱县| 太湖县| 大理市| 靖安县| 江孜县| 丰城市| 名山县| 玛曲县| 常宁市| 溧水县| 廉江市| 勐海县| 新化县| 衡南县| 专栏| 工布江达县| 永城市| 洞头县| 天长市| 昌黎县| 绥宁县| 惠水县| 新泰市| 漾濞| 临高县| 苗栗市| 金沙县| 东兰县| 唐海县| 南和县| 拉萨市| 巴彦淖尔市| 迁安市| 武陟县| 获嘉县| 南安市|