瞭解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();
        }
    }

但是下面的程式碼也可以是Decorator Pattern嗎?

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();
    }
}

我的理解

從我給出的第二個例子中,我們可以呼叫所有這三個方法,但從第一個例子開始,我無法通過建立單個物件來訪問所有這三個方法.

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

例如,您有一個物件和介面,如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();
    }
}

一旦你決定,就應該記錄對儲存庫的所有呼叫.但是你有一個問題 – Repository – 來自外部庫的類,你不想改變那些程式碼.因此,您需要擴充套件您使用的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.為什麼這是優勢?如果你決定寫自己的實現

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

你可以自動使用已經存在的裝飾器來裝飾它

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

想從真實軟體中看到例子嗎? (就像樣本,程式碼很難看,我知道)=> go here

涼!愛它! :d

翻譯自:https://stackoverflow.com/questions/40294622/understanding-decorator-design-pattern-in-c-sharp