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

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

利用Observer模式解決組件間通信問題

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

  1. 問題的提出
  以前做一個界面的時候經常會碰到這樣的尷尬情況:希望保留各個獨立的組件(類),但又希望它們之間能夠相互通信。譬如Windows中的EXPlorer,我們希望鼠標點擊左邊是樹型目錄的一個節點,右邊的文件瀏覽能及時列出該節點目錄下的文件和子目錄,類似這樣一個簡單的應用,假如只有一個類繼續JFrame,而樹型組件和瀏覽文件的面板作為成員,就像:
  public class MainFrame extends JFrame
  {
  JPanel treePanel;
  JTree tree;
  JPanel filePanel;
  ...
  }
  
  這樣當然輕易在兩者之間傳遞消息,但是可擴展性較差。通常輕易想到的是兩種辦法:在一個組件里保留另一個組件類型的成員,初始化時作為參數傳入引用,比如:
  class TreePanel extends JPanel
  {
  JTree tree;
  ...
  }
  
  class FilePanel extends JPanel
  {
  public FilePanel(JTree tree){...}
  ...
  }
  
  
  或者將一個組件線程化,不停地監聽另一個組件的變化,然后作出相應的反映,比如:
  class TreePanel extends JPanel
  {
  JTree tree;
  ...
  }
  
  class FilePanel extends JPanel implements Runnable
  {
  public void run()
  {
  while (true)
  {
  //監聽tree的變化
  }
  ...
  }
  ...
  }
  
  這樣確實可以達到我們的目的,但是第一種方案顯然不利于松散耦合,第二種方案比較占用系統資源。通過學習設計模式,我們發現可以用Observer模式來解決這個問題。
  
  2. Observer模式
  設計模式分為創建型、結構型和行為型,其中行為型模式專門處理對象間通信,指定交互方式等,Observer模式就是屬于行為型的一種設計模式。按照“四人幫”(Gang of Four)在“Design Patterns”里的定義,Observer模式“定義對象間的一種一對多的依靠關系,當一個對象的狀態發生改變時, 所有依靠于它的對象都得到通知并被自動更新”,這個描述正好符合我們對“組件通信”問題的需求。讓我們先看看Observer模式的結構:
  
  其中各元素的含義如下:
  Subject:被觀察的目標的抽象接口,它提供對觀察者(Observer)的注冊、注銷服務,Notify方法通知Observer目標發生改變;
  Object:觀察者的抽象接口,Update方法是當得到Subject狀態變化的通知后所要采取的動作;
  ConcreteSubject:Subject的具體實現;
  ConcreteObserver:Observer的具體實現
  Observer模式在實現MVC結構時非常有用,為數據和數據表示解耦合。
  
  3. java中的Observer模式:Observer和Observable
  在大致了解了Observer模式的描述之后,現在我們更為關心的是它在Java中是如何應用的。幸運的是,自從JDK 1.0起,就有了專門處理這種應用的API,這就是Observer接口和Observable類,它們是屬于java.util包的一部分。看來Java的開發者們真是深諳設計模式的精髓,而Java的確是為了真正的面向對象而生的,呵呵!
  這里的Observer和Observable分別對應設計模式中的Observer和Subject,對比一下它們定義的方法,痕跡還是相當明顯的:
  Observer的方法:
  update(Observable subject, Object arg) 監控subject,當subject對象狀態發生變化時Observer會有什么響應,arg是傳遞給Observable的notifyObservers方法的參數;
  Observable的方法:
  addObserver(Observer observer) observer向該subject注冊自己
  hasChanged() 檢查該subject狀態是否發生變化
  setChanged() 設置該subject的狀態為“已變化”
  notifyObservers() 通知observer該subject狀態發生變化
  
  4. Observer模式在Java GUI事件模型中應用
  其實在AWT/Swing事件模型中用到了好幾種設計模式,以前的JDK 1.0 AWT使用的是“基于繼續的事件模型”,在該模型Component類中定義了一系列事件處理方法,如:handleEvent,mouseDown,mouseUp等等,我們對事件的響應是通過對組件類繼續并覆蓋相應的事件處理方法的手段來實現,這種模型有很多缺點,事件的處理不應當由事件產生者負責,而且根據“設計模式”一書中的原則,“繼續”通常被認為是“對封裝性的破壞”,父子類之間的緊密耦合關系降低了靈活性,同時繼續輕易導致家族樹規模的龐大,這些都不利于組件可重用。
  JDK 1.1以后新的事件模型是被成為“基于授權的事件模型”,也就是我們現在所熟悉的Listener模型,事件的處理不再由產生事件的對象負責,而由Listener負責。尤其在Swing組件中設計MVC結構時用到了Observer模式,眾所周知,MVC表示“模型-視圖-控制器”,即“數據-表示邏輯-操作”,其中數據可以對應多種表示,這樣視圖就處在了observer的地位,而model則是subject。
  
  5. 簡單的例子
  回到本文一開始的那個Explorer的例子,我們考慮做一個簡單的圖片瀏覽器,使樹型選擇組件和圖片瀏覽面板在兩個不同的類中,其中圖片瀏覽面板根據所選擇的樹的節點顯示相應的圖片,所以圖片瀏覽面板是一個observer,樹是subject。由于Java單根繼續的原因,我們不能同時繼續JPanel和Observable,但可以用對象的組合把一個subject放到我們的類當中,并通過TreeSelectionListener觸發subject的setChanged方法,并通過notifyObservers方法通知observer。
  例子代碼如下:
  //LeFTPanel.java
  package com.jungleford.test;
  import java.awt.BorderLayout;
  import javax.swing.*;
  import javax.swing.event.TreeSelectionListener;
  import javax.swing.event.TreeSelectionEvent;
  import javax.swing.tree.DefaultMutableTreeNode;
  import java.util.Observable;
  import java.util.Observer;
  
  public final class LeftPanel extends JPanel
  {// 把樹型選擇視圖布局在左邊
  PRivate JTree tree;// 樹型選擇視圖
  private JScrollPane scroll;// 讓視圖可滾動
  private DefaultMutableTreeNode root, node1, node2;// 根節點及兩個葉子
  private Sensor sensor;// sensor是一個Observable,由于只能單根繼續,所以作為組合成員
  private String file;// 圖片文件名,與RightPanel通信的內容
  
  public LeftPanel(Observer observer)
  {
  file = "";
  sensor = new Sensor();
  sensor.addObserver(observer);// 向Observable注冊Observer
  root = new DefaultMutableTreeNode("Images");
  tree = new JTree(root);
  node1 = new DefaultMutableTreeNode("Rabbit");
  node2 = new DefaultMutableTreeNode("Devastator");
  root.add(node1);
  root.add(node2);
  tree.addTreeSelectionListener(new TreeSelectionListener()
  {// 樹節點選擇動作
  public void valueChanged(TreeSelectionEvent e)
  {
  Object obj = e.getPath().getLastPathComponent();
  if (obj instanceof DefaultMutableTreeNode)
  {
  DefaultMutableTreeNode node = (DefaultMutableTreeNode)obj;
  if (node == root)
  file = "";// 選擇根
  if (node == node1)
  file = "rabbit.jpg";// 選擇node1
  if (node == node2)
  file = "devastator.gif";// 選擇node2
  sensor.setData(file);// 改變Observable
  sensor.notifyObservers();// 通知observer,對象已改變
  }
  }
  });
  scroll = new JScrollPane(tree);
  add(scroll, BorderLayout.CENTER);
  }
  
  public Observable getSensor()
  {// 返回Observable對象,使Observer可以獲取
  return sensor;
  }
  }
  
  class Sensor extends Observable
  {// 定義自己的Observable
  private Object data;
  
  public void setData(Object newData)
  {
  data = newData;
  setChanged();// 改變Observable
  System.out.println("Data changed!");
  }
  
  public Object getData()
  {
  return data;
  }
  }
  
  //RightPanel.java
  package com.jungleford.test;
  import java.awt.*;
  import javax.swing.JPanel;
  import java.util.Observer;
  import java.util.Observable;
  
  public class RightPanel extends JPanel implements Observer
  {// 把圖片瀏覽視圖布局在右邊
  private Image image;
  
  public void update(Observable subject, Object obj)
  {// 定義接收到Observable變化后的響應動作
  String file = (String)((Sensor)subject).getData();
  if (!file.equals(""))
  {
  image = Toolkit.getDefaultToolkit().getImage(file);
  MediaTracker tracker = new MediaTracker(this);// 定義圖像跟蹤
  tracker.addImage(image, 0);
  try
  {
  tracker.waitForID(0);// 等待圖像的完全加載
  }
  catch (InterruptedException e)
  {
  e.printStackTrace();
  }
  }
  else
  image = null;
  repaint();// 重繪組件
  }
  
  public void paintComponent(Graphic

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 那曲县| 固原市| 成武县| 常宁市| 孝义市| 靖远县| 顺义区| 陆良县| 大邑县| 天镇县| 旬邑县| 巢湖市| 上高县| 嘉鱼县| 灌南县| 临清市| 昌江| 渭南市| 沈丘县| 承德市| 迁安市| 澳门| 交口县| 昭觉县| 仙游县| 龙泉市| 法库县| 封丘县| 丹阳市| 扶余县| 永泰县| 襄汾县| 娄底市| 县级市| 宣威市| 游戏| 潢川县| 丹江口市| 德阳市| 遂平县| 高台县|