2012-12-20 42 views
9

我有这个简单的类:Decorator模式的类的许多属性

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

话,我想为它创建一个装饰,将添加一串它自己的特性。问题是提供访问装饰性属性的最简洁和优雅的方式?

到目前为止,我有两个选择:要么我在装饰提供get-set对,每四个装饰性(至极似乎tideous和满口,基本上这是我想避免的)或我继承DataBagDynamicObject然后以某种方式管理使用TryGetMember方法(这是动态的,似乎不是在C#中执行任何操作的正确方法)获取装饰属性。

有什么建议吗?

+0

通常,装饰器都从一个通用接口继承。在这种情况下,该接口会是什么?如果它是动态的,那么装饰者可能不适合。 –

+0

你有没有考虑过装饰器*从'DataBag'继承*?唯一的问题是你不能从装饰者向下投射基础类型。 – McGarnagle

+0

@dbaseman我最初使用了继承,但很快就遇到了需要很多具有稍微不同属性和方法的类的情况。 – Anton

回答

7

在实现装饰我平时以下。首先 - 提取饰对象的接口,使装饰对象实现该接口:

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

更新:@JeremyDWill正确地指出,你不能从它的一个参数推导出泛型类型...

如果你想装饰作为一个“子类,​​增加了新的属性”,你可以这样做: MyDecorator<OtherClass>MyDecorator<DataBag>

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

然后你就可以创建实例,等现有的属性是可访问的,因为 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()); 
+1

它与简单继承“MyDataBagDecorator:DataBag”有什么不同?另外通常为一个装饰对象创建许多装饰器,而不是许多不同类型对象的装饰器。 –

+0

@lazyberezovsky:装饰者通常不是特定于一个类。如果是,他们只是一个子类,而不是装饰者。至于有多个装饰器,这一切都取决于上下文,这就是为什么一个段落开始“如果你不能从装饰品子类...”。幸运的是,在您添加评论的同时,我正在撰写我的“附加装饰”解决方案! – JaredReisinger

+0

在这种情况下,装饰器不会有任何有关T成员的知识,因此无法访问它们。我认为这个解决方案是最好的,但T应该被迫实现一个接口。 –

1

这是装饰最简单的方法:

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

如果你想CR吃掉一个外观并隐藏一些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; } 
    }