2012-02-20 152 views
12

我相信瞭解設計師模式與訪客設計模式的意圖。設計師設計模式與訪客設計模式的區別

雖然我可以列出下列差別

  1. 裝飾工程的對象上,訪問者適用於複合結構,
  2. 裝飾是結構設計圖案,訪客是行爲的設計模式。

當我深思下去時,我無法說服自己兩者之間的真正區別是什麼。

回答

15

那麼,他們實際上是不同的,因爲他們可以!

使用修飾器當你想用一些新的,或多或少的透明功能如驗證或緩存來增強現有對象時。看到這裏例如:Should I extend ArrayList to add attributes that isn't null?

,另一方面遊客當你有一個類的層次結構,並要根據具體類型,但避免instanceoftypeof運營商運行不同的方法使用。見活生生的例子:Is This Use of the "instanceof" Operator Considered Bad Design?

裝飾工程的對象上,參觀者適用於複合材料結構,

遊客作品在繼承層次,複合是一個不同的GoF設計模式。

裝飾是結構設計模式,訪客是行爲設計​​模式。

確實如此,但它並不能真正幫助理解它們的工作原理嗎?

7

設計模式並不意味着在實現差異但什麼時候應該使用一種或另一種分類。

它們用於完全不同的目的:

  • ,當你想通過提供裝飾其他對象單一元素動態充實對象的功能,使它們真正添加一些行爲,他們(你會用裝飾實際上它是在這個意義上結構模式,它改變了你與沃金
  • 當你想一個算法從它使用的對象分開,你會使用訪問者的對象)的結構。你所做的是你有這個訪問者被傳遞給多個不同的對象,通常是一個層次結構(他們被稱爲接受訪問者),這個訪問者根據它正在訪問的對象的類型具體的時刻。通過這種方式,您可以讓訪問者根據特定對象做任何事情,而無需在對象本身中指定這些操作(這就是爲什麼它是行爲)。這是一種抽象方法,沒有在對象本身中定義。
2

我喜歡認爲裝飾器允許避免繼承,然後擴展類,因爲儘管你以某種方式繼承,但OOP的一般原則是偏好聚合而非繼承。這裏是一個過於簡單的例子

abstract class Chef{ 
    public abstract void Prepare(); 
} 

class CookieMaker:Chef{   //Concrete class 
    public override void Prepare() 
    { 
     //Bake in Oven 
    } 
} 

    // Decorator class 
// This chef adds chocolate topping to everything 
class ChocoChef:Chef{ 

    public ChocoChef(Chef mychef) 
    { 
     this.chef = mychef; 
    } 

    public override void Prepare() 
    { 
      // Add chocolate topping first 
      chef.Prepare() 
    } 
} 

我爲了空間的緣故縮短了一些細節。例如,你可以抽出一名廚師,添加任何種類的頂部,然後ChocoChef成爲其具體的類。現在,無論您準備什麼,ChocoChef都會添加巧克力配料。所以現在你可以通過將相應的廚師傳遞給它的構造者來獲得巧克力餅乾或巧克力蛋糕。另一方面,訪問者對對象起作用,並決定根據訪問對象做些事情。

class Student{ 
    // Different visitors visit each student object using this method 
    // like prize distributor or uniform inspector 
    public Accept(IVisitor v) 
    { 
     v.Visit(this) 
    } 
} 

// Visitor visits all student OBJECTS 
class PrizeDistributor:IVisitor{ 
    public override void Visit(Student s) 
    { 
      // if(s has scored 100) 
      // Award prize to s 
    } 
} 
1

我解釋的方式,參觀者表示,我們可能要採取或物體的動作,但不一定是固有的對象,並且是關係,而水平。例如,我可以爲一輛汽車「做一個營銷宣傳」,但我不會爲汽車對象設計一個「createMarketingPitch」功能,因爲這對於在我的汽車對象上創建許多功能將是一個滑坡。

另一方面,裝飾器是一種模式,它在現有對象之上分層功能,垂直關係用於修改對象在調用正常功能時的行爲方式。此外,雖然訪問者被編碼爲使用一類對象,但可將裝飾者分配給對象的特定實例,以便相同類型的不同實例的行爲不同於彼此。

+0

+1爲了描述「水平關係」的訪問者模式,這有助於我可視化何時以及爲什麼使用它。 – ryanp102694 2017-04-26 09:26:57

0

它們都將「添加功能」添加到現有對象,而無需修改原始類。所不同的是:

隨着裝飾你加一個包裝,這個對象具有基本功能的功能(例如,除了執行一些基本的動作也將其寫入日誌,除了將文件寫入到磁盤中也對其進行加密) 。這也允許我們創建不同的裝飾器組合,而不需要爲每個可能的場景劃分子類。

與顧客你加你不想定義爲基本組件類本身(甚至還不如一個包裝基本功能),例如由於單一職責原則,開放的一部分,一個完全新的行爲關閉原則等。 當相同類型的不同子類之間的行爲不同時(如果沒有任何複雜的子類結構但只有一個類可以創建一個新類並通過構圖包含原始類,並且仍然達到不影響或修改原始類別的目標)。這樣你就可以避免編寫像if (a is ConcreteClass1) {...} else if (a is ConcreterClass2) {...}這樣的代碼,而無需編寫虛擬方法。

由於這種差異,使用裝飾器,客戶端代碼調用基本組件類的接口上定義的相同方法,現在它只是「裝飾」了額外的功能,而客戶端調用一些常規「接受」方法並向其發送訪問者。

0

我想裝飾模式的方式是當我想在運行時添加功能的對象。在程序運行時,我可以通過將對象包裝到可以擴展其方法的裝飾器類中將對象添加到對象中。

對於訪問者模式,我喜歡它,當我必須對同一類型的「一組」對象進行操作並收集信息時。比方說,我有10個具體的蔬菜類,我想知道所有10個蔬菜的總價。我可以使用訪客模式來「訪問」每個蔬菜對象,並且在迭代結束時我會有總價。當然,您也可以使用該模式作爲將某個操作與對象分離的一種方式。

0

Decorator

裝飾圖案可以被用來靜態延伸(裝飾)的某個對象的功能,或在某些情況下在運行時,獨立地是相同類的其他實例的,提供了一些基礎工作在設計時完成

何時使用裝飾模式?

  1. 對象職責和行爲應該是動態添加/移除
  2. 混凝土實現應該從責任去耦和行爲
  3. 當子 - 分級過於昂貴動態地添加/刪除責任

相關文章:

When to Use the Decorator Pattern?

Visitor

訪問者設計模式是從在其它操作對象結構分離的算法的方法。這種分離的實際結果是能夠在不修改這些結構的情況下向現有對象結構添加新的操作。這是遵循開放/封閉原則的一種方式。

何時使用訪客模式?

  1. 類似的操作都必須在一個結構
  2. 您需要執行很多不同的和無關的業務組合不同類型的對象進行的。它從物體結構分離操作
  3. 新業務有沒有對象結構的變化將被添加
  4. 收集相關操作成一個類,而不是強迫你改變或派生的類
  5. 添加功能的類庫,你要麼沒有來源或不能更改源

相關崗位:

When should I use the Visitor Design Pattern?

相關鏈接:

sourcemaking裝飾條

oodesign遊客文章

sourcemaking遊客文章

0

是的,他們都添加一些功能,在運行時的現有系統,並儘量少一些被動反應(在一個很好的意義上)動態變化,但有一些差異。

訪問者主要是爲了尊重OCP(有時是SRP),以使系統更加靈活。隨着程序的發展,您可以添加任何訪問者,而無需更改現有系統。但是,您需要以事先設定系統。你不能爲已經運行的系統添加一個新的Visitor類(或模式),並期望它不用重新編譯,重新測試或者任何其他的工作。另一方面,您可以使用裝飾器通過將抽象基類(您已有的)包裝到裝飾器中來豐富現有系統的功能,並將您豐富的特性作爲單獨的對象提供,以便您可以您可以根據需要進行創建。而且,在語義上,裝飾者相當於指出某物的出現。

哪一個更喜歡?海事組織,回答這可能會更有幫助。對我而言,我不喜歡裝飾者使用基類的方式。它都使用繼承和聚合。如果您需要更改此類(wrapee),則最終將重新編譯整個層次結構/模塊。但它很方便,您可以在設計時間後更改行爲。另一方面,在Visitor模式中,我不喜歡在Visitor實現中瞭解每個具體類型的想法。當你添加一個新的基類類型時,你也需要去改變Visitor類來添加它。但是,當您需要代碼注入到現有系統而不改變結構或您需要分離課程中的問題(單用戶響應)時,此功能很有用。

最後,什麼讓Visitor比普通繼承更好?依靠。使用繼承你將更加依賴於接口簽名。使用訪問者使您的訪問者類依賴於具體的類。更不用提你在不改變現有模塊簽名的情況下使用訪問者添加更多行爲,而不是在現有類中實現新的接口。