2016-10-27 65 views
6

我剛開始學習裝飾器設計模式,不幸的是我不得不通過各種參考來更好地理解裝飾器模式,這導致我非常困惑。所以,據我的理解是擔憂,我相信這是一個裝飾圖案瞭解C裝飾器設計模式#

interface IComponent 
    { 
     void Operation(); 
    } 
    class Component : IComponent 
    { 
     public void Operation() 
     { 
      Console.WriteLine("I am walking "); 
     } 
    } 
    class DecoratorA : IComponent 
    { 
     IComponent component; 
     public DecoratorA(IComponent c) 
     { 
      component = c; 
     } 
     public void Operation() 
     { 
      component.Operation(); 
      Console.WriteLine("in the rain"); 
     } 
    } 
    class DecoratorB : IComponent 
    { 
     IComponent component; 
     public DecoratorB(IComponent c) 
     { 
      component = c; 
     } 
     public void Operation() 
     { 
      component.Operation(); 
      Console.WriteLine("with an umbrella"); 
     } 
    } 
    class Client 
    { 
     static void Main() 
     { 
      IComponent component = new Component(); 
      component.Operation(); 

      DecoratorA decoratorA = new DecoratorA(new Component()); 
      component.Operation(); 

      DecoratorB decoratorB = new DecoratorB(new Component()); 
      component.Operation(); 

      Console.Read(); 
     } 
    } 

,但可以在下面的代碼也是裝飾模式?

class Photo 
{ 
    public void Draw() 
    { 
     Console.WriteLine("draw a photo"); 
    } 
} 
class BorderedPhoto : Photo 
{ 
    public void drawBorder() 
    { 
     Console.WriteLine("draw a border photo"); 
    } 
} 
class FramePhoto : BorderedPhoto 
{ 
    public void frame() 
    { 
     Console.WriteLine("frame the photo"); 
    } 
} 
class Client 
{ 
    static void Main() 
    { 
     Photo p = new Photo(); 
     p.Draw(); 

     BorderedPhoto b = new BorderedPhoto(); 
     b.Draw(); 
     b.drawBorder(); 

     FramePhoto f = new FramePhoto(); 
     f.Draw(); 
     f.drawBorder(); 
     f.frame(); 
    } 
} 

我的理解

從我給出的第二個例子中,我們可以調用所有這三種方法,但是從第一個例子,我將無法通過創造讓所有三種方法訪問一個單一的對象。

+0

1 - 裝飾者,2 - 不是。從我的角度來說,裝飾者應該包裝裝飾物:) – tym32167

+1

裝飾者是想延伸的方法吧!!!那爲什麼第二個不是Decorator模式?你能幫我理解嗎? –

+2

@LijinJohn我會說這是因爲一個裝飾器* *裝飾現有的實例。如果我已經有一個'Photo'的實例,我不能簡單地使用'BorderedPhoto'來裝飾它,我不得不創建一個'BorderedPhoto'的實例,然後從我的原始'Photo'實例複製屬性。這不是裝飾。 – Kyle

回答

7

它應該是一個評論,但我有太多的話。

例如,您有一個對象和接口,如Repository : IRepository

public interface IRepository 
{ 
    void SaveStuff(); 
} 

public class Repository : IRepository 
{ 
    public void SaveStuff() 
    { 
     // save stuff 
    } 
} 

和客戶端,這可能不是由你

class RepoClient 
{ 
    public void DoSomethig(IRepository repo) 
    { 
     //... 
     repo.SaveStuff(); 
    } 
} 

writen一旦你決定,即到庫中的所有呼叫應當被記錄。但是你有一個問題 - 從外部庫的庫 - 類,你不想改變那個代碼。所以你需要擴展你使用的Repository的行爲。你寫RepositoryLogDecorator : IRepository了,裏面的每個方法做記錄,就像

public class RepositoryLogDecorator : IRepository 
{ 
    public IRepository _inner; 

    public RepositoryLogDecorator(IRepository inner) 
    { 
     _inner = inner; 
    } 

    public void SaveStuff() 
    { 
     // log enter to method 
     try 
     { 
      _inner.SaveStuff(); 
     } 
     catch(Exception ex) 
     { 
      // log exception 
     }  
     // log exit to method 
    } 
} 

所以,在你可以使用客戶端作爲

var client = new RepoClient(); 
client.DoSomethig(new Repository()); 

但現在你可以使用

var client = new RepoClient(); 
client.DoSomethig(new RepositoryLogDecorator(new Repository())); 

。注意,這是一個非常簡單的例子。在真正的項目中,對象使用DI容器創建主要對象,您可以通過更改某些配置來使用裝飾器。

因此,使用裝飾器的是:在不改變對象或客戶端的情況下擴展對象的功能。

裝飾者的另一個好處是:你的裝飾者不取決於Repository的實現。僅取決於界面IRepository。爲什麼這是優勢?如果您somewhen將決定寫你自己實現

public class MyAwesomeRepository : IRepository 
{ 
    public void SaveStuff() 
    { 
     // save stuff, but AWESOME! 
    } 
} 

您自動能夠與裝飾裝飾這一點,已經存在

var client = new RepoClient(); 
client.DoSomethig(new RepositoryLogDecorator(new MyAwesomeRepository())); 

想看看例如,從真正的軟件? (就像樣品,代碼是醜陋的,我知道)=>go here

很酷!愛它! :D

+0

先生,非常感謝你的幫助:) –

0

第二個例子不是裝飾模式,因爲裝飾模式的基本要素是對象接受其中一種並可能增強它。

在第一實施例這方面的一個實例是

public DecoratorA(IComponent c) { component = c; }

另外,裝飾圖案的目標是創建「一」對象,然後將其通過不同的濾波器或裝飾裝飾。 因此,線

DecoratorA decoratorA = new DecoratorA(new Component());

應該

DecoratorA decoratorA = new DecoratorA(component);

2

Decorator模式可以讓你到一個特定的行爲添加到特定類型的單個對象,而不會影響其他實例相同的類型。

在你的第二個例子中,這是正常的繼承,這個類的所有實例都繼承了修改後的行爲。

1

GOF page裝飾德興圖案:

附加額外的責任來動態的對象。裝飾器爲擴展功能提供了子類化的靈活替代方案。

在第二個例子中,你正在使用繼承來擴展類的行爲,我認爲這在技術上是不是一個裝飾設計模式。

2

有這個PatternCraft series on Youtube解釋與星際爭霸的設計模式,你應該check the video about Decorators here

在上面的視頻中,作者以MarineWeaponUpgrade爲例。

在遊戲中你將有一個Marine,然後你可以升級它的武器:

marine = new WeaponUpgrade(marine); 

注意,你仍然有海洋存在,它不是一個新的單位,它與事物的相同單元修改其屬性。

public class MarineWeaponUpgrade : IMarine 
{ 
    private IMarine marine; 

    public MarineWeaponUpgrade(IMarine marine) 
    { 
     this.marine = marine; 
    } 

    public int Damage 
    { 
     get { return this.marine.Damage + 1; } // here 
     set { this.marine.Damage = value; } 
    } 
} 

您可以通過創建一個實現與您的設備相同接口的類並訪問您的設備屬性來修改值。

有一個Kata on CodeWars挑戰你完成一個海洋武器和裝甲裝飾。

+0

謝謝你的youtube鏈接,視頻是有幫助的:) –