1. 程式人生 > 其它 >設計模式之行為型模式-1. 迭代器模式與訪問者模式

設計模式之行為型模式-1. 迭代器模式與訪問者模式

 行為型模式

一、行為型模式簡介

  • 迭代器模式(Iterator)
  • 訪問者模式(Visitor) 
  • 命令模式(Command) 
  • 直譯器模式(Interpreter)
  • 職責鏈模式(Chain of Responsibility)
  • 備忘錄模式(Memento)
  • 中介者模式(Mediator)
  • 觀察者模式(Observer)
  • 狀態模式(State)
  • 策略模式(Strategy)
  • 模板方法模式(Template Method)  

 1. 迭代器模式

  1.1 模式動機

    (1)一個聚合物件,如一個列表(List)或者一個集合(Set),應該提供一種方法來讓別人可以訪問它的元素,而又不需要暴露它的內部結構

  (2)針對不同的需要,可能還要以不同的方式遍歷整個聚合物件,但是我們並不希望在聚合物件的抽象層介面中充斥著各種不同遍歷的操作。

  (3)怎樣遍歷一個聚合物件,又不需要了解聚合物件的內部結構,還能夠提供多種不同的遍歷方式,這就是迭代器模式所要解決的問題

  (4)在迭代器模式中,提供一個外部的迭代器來對聚合物件進行訪問和遍歷,迭代器定義了一個訪問該聚合元素的介面,並且可以跟蹤當前遍歷的元素,瞭解哪些元素已經遍歷過而哪些沒有。

  (5) 有了迭代器模式,我們會發現對一個複雜的聚合物件的操作會變得如此簡單。

                             

  1.2 模式定義

    迭代器模式(Iterator Pattern) :提供一種方法來訪問聚合物件,而不用暴露這個物件的內部表示,其別名為遊標(Cursor)。迭代器模式是一種物件行為型模式。

       1.3 模式結構

    迭代器模式包含如下角色:

  •  Iterator: 抽象迭代器   定義了訪問和遍歷元素的介面
  • ConcreteIterator: 具體迭代器  

                 實現了抽象迭代器介面,完成對聚合物件的遍歷。

 1.4 模式分析

  • 聚合是一個管理和組織資料物件的資料結構。
  • 聚合物件主要擁有兩個職責:一是儲存內部資料;二是遍歷內部資料。
  • 儲存資料是聚合物件最基本的職責。
  • 將遍歷聚合物件中資料的行為提取出來,封裝到一個迭代器中,通過專門的迭代器來遍歷聚合物件的內部資料,這就是迭代器模式的本質。迭代器模式是“單一職責原則”的完美體現。
  • 在迭代器模式中應用了工廠方法模式聚合類充當工廠類,而迭代器充當產品類,由於定義了抽象層,系統的擴充套件性很好,在客戶端可以針對抽象聚合類和抽象迭代器進行程式設計。

  • 由於很多程式語言的類庫都已經實現了迭代器模式,因此在實際使用中我們很少自定義迭代器,只需要直接使用Java、C#等語言中已定義好的迭代器即可,迭代器已經成為我們操作聚合物件的基本工具之一

  1.5 模式優缺點

              1.5.1  迭代器模式的優點 :

  • 它支援以不同的方式遍歷一個聚合物件。
  • 迭代器簡化了聚合類。
  • 在同一個聚合上可以有多個遍歷。
  • 在迭代器模式中,增加新的聚合類和迭代器類都很方便,無須修改原有程式碼,滿足“開閉原則”的要求。

    1.5.2 迭代器模式的缺點:

  • 由於迭代器模式將儲存資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類類的個數成對增加,這在一定程度上增加了系統的複雜性。

  1.6 模式適用環境

    在以下情況下可以使用迭代器模式:

  • 訪問一個聚合物件的內容而無須暴露它的內部表示。
  • 需要為聚合物件提供多種遍歷方式。
  • 為遍歷不同的聚合結構提供一個統一的介面

       1.7 模式應用

  • JDK 1.2 引入了新的Java聚合框架Collections。
  • Collection是所有Java聚合類的根介面。

  • 在JDK類庫中,Collection的iterator()方法返回一個java.util.Iterator型別的物件,而其子介面java.util.List的listIterator()方法返回一個java.util.ListIterator型別的物件,ListIterator是Iterator的子類。                                                                     它們構成了Java語言對迭代器模式的支援,Java語言的java.util.Iterator介面就是迭代器模式的應用。

   1.8 模式擴充套件

    Java迭代器

      在JDK中,Iterator介面具有如下3個基本方法:

        (1) Object next():通過反覆呼叫next()方法可以逐個訪問聚合中的元素。

        (2) boolean hasNext():hasNext()方法用於判斷聚合物件中是否還存在下一個元素,為了不丟擲異常,必須在呼叫next()之前先呼叫hasNext()。如果迭代物件仍然擁有可供訪問的元素,那麼hasNext()返回true。

         (3) void remove():用於刪除上次呼叫next()時所返回的元素。 

   1.9  模式案例

             電視機遙控器:有一個地方頻道集合,另一個是央視訊道,將不同型別的頻道,進行統一管理,能實現所有頻道的前後選擇。

                                

  2.  訪問者模式 

         2.1 模式動機

      對於系統中的某些物件,它們儲存在同一個集合中,且具有不同的型別,而且對於該集合中的物件,可以接受一類稱為訪問者的物件來訪問,

     而且不同的訪問者其訪問方式有所不同,訪問者模式為解決這類問題而誕生。        如:醫院的劃價人員和藥房的工作人員

     2.2   模式動機

      在實際使用時,對同一集合物件的操作並不是唯一的,對相同的元素物件可能存在多種不同的操作方式。

      而且這些操作方式並不穩定,可能還需要增加新的操作,以滿足新的業務需求。

      此時, 訪問者模式就是一個值得考慮的解決方案。

         訪問者模式的目的(即動機)

  • 封裝一些施加於某種資料結構元素之上的操作,一旦這些操作需要修改的話,接受這個操作的資料結構可以保持不變
  • 為不同型別的元素提供多種訪問操作方式,且可以在不修改原有系統的情況下增加新的操作方式。

    2.3 模式定義

    訪問者模式(Visitor Pattern):表示一個作用於某物件結構中的各元素操作,它使我們可以在不改變各元素的類的前提下定義作用於這些元素的新操作。訪問者模式是一種物件行為型模式。

   

    2.4 模式結構

                                 

 

  訪問者模式包含如下角色:

  • Vistor: 抽象訪問者
  • ConcreteVisitor:具體訪問者
  • Element: 抽象元素
  • ConcreteElement: 具體元素
  • ObjectStructure: 物件結構

      

  2.5  模式分析

  • 訪問者模式中物件結構儲存了不同型別的元素物件,以供不同訪問者訪問。
  • 訪問者模式包括兩個層次結構,一個是訪問者層次結構,提供了抽象訪問者和具體訪問者,一個是元素層次結構,提供了抽象元素和具體元素。
  • 相同的訪問者可以以不同的方式訪問不同的元素,相同的元素可以接受不同訪問者以不同訪問方式訪問。
  • 在訪問者模式中,增加新的訪問者無須修改原有系統,系統具有較好的可擴充套件性。

  2.6 模式例項 

        獎勵審批系統 某高校獎勵審批系統可以實現教師獎勵和學生獎勵的審批(AwardCheck),如果教師發表論文數超過10篇或者學生論文超過2篇可以評選科研獎,

             如果教師教學反饋分大於等於90分或者學生平均成績大於等於90分可以評選成績優秀獎,使用訪問者模式設計該系統,以判斷候選人集合中的教師或學生是否符合某種獲獎要求。

         2.7   模式優缺點

    訪問者模式的優點

  • 使得增加新的訪問操作變得很容易
  • 將有關元素物件的訪問行為集中到一個訪問者物件中,而不是分散到一個個的元素類中。
  • 可以跨過類的等級結構訪問屬於不同的等級結構的元素類。
  • 讓使用者能夠在不修改現有類層次結構的情況下,定義該類層次結構的操作。

    訪問者模式的缺點

  • 增加新的元素類很困難。在訪問者模式中,每增加一個新的元素類都意味著要在抽象訪問者角色中增加一個新的抽象操作,並在每一個具體訪問者類中增加相應的具體操作,違背了“開閉原則”的要求。
  • 破壞封裝。訪問者模式要求訪問者物件訪問並呼叫每一個元素物件的操作,這意味著元素物件有時候必須暴露一些自己的內部操作和內部狀態,否則無法供訪問者訪問。

  2.8  模式適用環境

  在以下情況下可以使用訪問者模式:

  • 一個物件結構包含很多型別的物件,希望對這些物件實施一些依賴其具體型別的操作。在訪問者中針對每一種具體的型別都提供了一個訪問操作,不同型別的物件可以有不同的訪問操作。
  • 需要對一個物件結構中的物件進行很多不同的並且不相關的操作,而需要避免讓這些操作“汙染”這些物件的類,也不希望在增加新操作時修改這些類
  • 訪問者模式使得我們可以將相關的訪問操作集中起來定義在訪問者類中,物件結構可以被多個不同的訪問者類所使用,將物件本身與物件的訪問操作分離。
  • 物件結構中物件對應的類很少改變,但經常需要在此物件結構上定義新的操作

  2.9 模式應用

  (1) 在一些編譯器的設計中運用了訪問者模式,程式程式碼是被訪問的物件,它包括變數定義、變數賦值、邏輯運算、算術運算等語句,編譯器需要對程式碼進行分析,如檢查變數是否定義、變數是否賦值、算術運算是否合法等,可以將不同的操作封裝在不同的類中,如檢查變數定義的類、檢查變數賦值的類、檢查算術運算是否合法的類,這些類就是具體訪問者可以訪問程式程式碼中不同型別的語句。在編譯過程中除了程式碼分析外,還包含程式碼優化、空間分配和程式碼生成等部              分,也可以將每一個不同編譯階段的操作封裝到了跟該階段有關的一個訪問者類中

  2.10 模式擴充套件

  • 與其他模式聯用 由於訪問者模式需要對物件結構進行操作,而物件結構本身是一個元素物件的集合,因此訪問者模式經常需要與迭代器模式聯用,在物件結構中使用迭代器來遍歷元素物件。
  • 在訪問者模式中,元素物件可能存在容器物件和葉子物件,因此可以結合組合模式來進行設計。
  • 傾斜的“開閉原則” 訪問者模式以一種傾斜的方式支援“開閉原則”,增加新的訪問者方便,但是增加新的元素很困難。

  購物車

顧客在超市中將選擇的商品,如蘋果、圖書等放在購物車中,然後到收銀員處付款。在購物過程中,顧客需要對這些商品進行訪問,以便確認這些商品的質量,之後收銀員計算價格時也需要訪問購物車內顧客所選擇的商品。此時,購物車作為一個ObjectStructure(物件結構)用於儲存各種型別的商品,而顧客和收銀員作為訪問這些商品的訪問者,他們需要對商品進行檢查和計價。不同型別的商品其訪問形式也可能不同,如蘋果需要過秤之後再計價,而圖書不需要。使用訪問者模式來設計該購物過程。