12

私はこの単純なクラスを持っています:

public class DataBag
{
    public string UserControl { get; set; }
    public string LoadMethod { get; set; }
    public dynamic Params { get; set; }
    public int Height { get; set; }

    public DataBag(string Control, 
        object vars, string lm)
    {
        UserControl = Control;
        LoadMethod = lm;
        Params = vars;
        Height = 0;
    }
}

次に、独自のプロパティを追加するデコレータを作成したいと思います。質問は、装飾されたプロパティへのアクセスを提供する最も簡潔でエレガントな方法は何ですか?

これまでのところ、私には 2 つのオプションがあります。get-setデコレータで 4 つの装飾されたプロパティのすべてにペアを提供するか (これは退屈で一口に思えるので、基本的には避けたいことです)、継承DataBagしてからメソッドDynamicObjectを使用して装飾されたプロパティを取得するTryGetMember方法 (これは動的であり、C# で行う正しい方法ではないようです)。

何かアドバイス?

4

3 に答える 3

9

デコレータを実装するとき、私は通常次のことを行います。最初に-装飾されたオブジェクトのインターフェイスを抽出し、装飾されたオブジェクトにそのインターフェイスを実装させます。

public interface IDataBag
{
    string UserControl { get; set; }
    string LoadMethod { get; set; }
    dynamic Params { get; set; }
    int Height { get; set; }
}

次へ-デコレータを作成します。デコレータは、装飾されたオブジェクトへのすべての呼び出しを委任します(すべてのデコレータはこのデコレータから継承します)。

public class DataBagDecorator : IDataBag
{
    private IDataBag _dataBag;

    public DataBagDecorator(IDataBag dataBag)
    {
        _dataBag = dataBag;
    }

    public virtual string UserControl
    {
        get { return _dataBag.UserControl; }
        set { _dataBag.UserControl = value; }
    }

    // other members
}

最後-デコレータの作成:

public class FooDataBag : DataBagDecorator
{
    public FooDataBag(IDataBag dataBag) 
        : base(dataBag) { }

    public override string UserControl
    {
        // added behavior
        get { return "Foo" + base.UserControl; }
        set { base.UserControl = value; }
    }

    // you don't need to override other members
}

使用法:

IDataBag dataBag = new FooDataBag(new DataBag());
于 2012-12-20T22:02:28.970 に答える
1

これは装飾する最も簡単な方法です:

public class PrettyBag : DataBag
{
    public int Decoration1 { get; set; }
    public int Decoration2 { get; set; }
}

プロパティを追加するだけでなく、ファサードを作成してDataBagプロパティの一部を非表示にする場合は、DataBagのメンバーを保護することができます。

インターフェースを使用すると、次のことができます。

    public interface IDataBag
    {
       ...
    }
    public class DataBag : IDataBag
    {
       ...
    }
    public interface IPrettyBag : IDataBag
    {
        int Decoration1 { get; set; }
        int Decoration2 { get; set; }
    }
    public class BigBag : IPrettyBag
    {
        public int Decoration1 { get; set; }
        public int Decoration2 { get; set; }
    }
    public interface SmallBag : IPrettyBag
    {
        public int Decoration1 { get; set; }
        public int Decoration2 { get; set; }
    }
于 2012-12-20T22:00:58.213 に答える
1

更新: @JeremyDWill は、そのパラメーターの 1 つからジェネリック型を派生させることはできないと正しく指摘しました...

デコレーターを「新しいプロパティを追加するサブクラス」と考えると、次のようにすることができます。

public class MyDecorator<T> : T
{
    public int MyDecoratorProperty1 { get; set; }
    public int MyDecoratorProperty2 { get; set; }
}

MyDecorator<DataBag>その後、 、 、 などのインスタンスを作成できます。はジェネリック引数の型に固有であり、そのクラスから派生しているMyDecorator<OtherClass>ため、既存のプロパティにアクセスできます。MyDecorator<>

装飾されたオブジェクトを含むラッパーを作成できます。

public class MyDecorator<T>
{
    public MyDecorator(T decoratedObject)
    {
        this.DecoratedObject = decoratedObject;
    }

    public T DecoratedObject { get; private set; }

    public int MyDecoratorProperty1 { get; set; }
    public int MyDecoratorProperty2 { get; set; }
}

利点は、装飾されたプロパティに簡単にアクセスできることです: myObj.MyDecoratorProperty1. DecoratedObject欠点は、基本オブジェクトに到達するためにメンバーを通過する必要があることです。

DataBag bag = new DataBag("", null, null);
MyDecorator<DataBag> deco = new MyDecorator<DataBag>(bag);
deco.DecoratedObject.Height = 2;

装飾からサブクラス化できない場合 (たとえば、一度に複数のデコレーターをサポートする必要がある場合)、「添付プロパティ」のようなことを行う必要があります...デコレーター クラスは元の辞書を保持する必要があります。オブジェクトと装飾されたプロパティ。いくつかの拡張メソッドを使用して、これらのプロパティを装飾されたクラスのネイティブ メンバーのように "見える" ようにすることができます

public static class AttachedDecorator
{
    private class Properties
    {
        public int MyDecoratorProperty1 { get; set; }
        public int MyDecoratorProperty2 { get; set; }
    }

    private static Dictionary<object, Properties> map = new Dictionary<object, Properties>();

    public static int GetMyDecoratorProperty1(object obj)
    {
        Properties props;
        if (map.TryGetValue(obj, out props))
        {
            return props.MyDecoratorProperty1;
        }

        return -1; // or some value that makes sense if the object has no decorated property set
    }

    public static int GetMyDecoratorProperty2(object obj) { /* ... */ }

    public static void SetMyDecoratorProperty1(object obj, int value)
    {
        Properties props;
        if (!map.TryGetValue(obj, out props))
        {
            props = new Properties();
            map.Add(obj, props);
        }

        props.MyDecoratorProperty1 = value;

    }

    public static void SetMyDecoratorProperty2(object obj, int value) { /* ... */ }
}

public static class DecoratorExtensions
{
    private static int GetMyDecoratorProperty1(this object obj)
    {
        return AttachedDecorator.GetMyDecoratorProperty1(obj);
    }

    private static void SetMyDecoratorProperty1(this object obj, int value)
    {
        return AttachedDecorator.GetMyDecoratorProperty1(obj, value);
    }
    // ...
}

コードは次のようになります。

DataBag myData = new DataBag();
myData.SetMyDecoratorProperty1(7);
Console.WriteLine("prop1: {0}", myData.GetMyDecoratorProperty1());
于 2012-12-20T21:46:26.043 に答える