Cập nhật: đúng @JeremyDWill chỉ ra rằng bạn không thể lấy được một kiểu generic từ một trong các thông số của nó ...
Nếu bạn nghĩ về trang trí như một "lớp con có thêm thuộc tính mới", bạn có thể làm một cái gì đó như:
public class MyDecorator<T> : T
{
public int MyDecoratorProperty1 { get; set; }
public int MyDecoratorProperty2 { get; set; }
}
Sau đó, bạn có thể tạo ra các trường hợp
MyDecorator<DataBag>
, và
MyDecorator<OtherClass>
vv các tính chất hiện có thể truy cập vì
MyDecorator<>
là cụ thể cho các loại lập luận chung chung, và xuất phát từ lớp đó.
Bạn có thể tạo một wrapper chứa các đối tượng trang trí:
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; }
}
Ưu điểm là nhận được các thuộc tính trang trí rất dễ dàng: myObj.MyDecoratorProperty1
. Nhược điểm là bây giờ bạn phải đi qua các DecoratedObject
thành viên để có được các đối tượng cơ sở:
DataBag bag = new DataBag("", null, null);
MyDecorator<DataBag> deco = new MyDecorator<DataBag>(bag);
deco.DecoratedObject.Height = 2;
Nếu bạn không thể phân lớp từ decorate (bạn cần hỗ trợ nhiều trang trí cùng một lúc, nói), bạn sẽ phải làm một cái gì đó như một "thuộc tính đính kèm" ... lớp trang trí của bạn sẽ phải giữ một từ điển của các đối tượng ban đầu và các thuộc tính được trang trí. Với một vài phương pháp mở rộng, bạn có thể làm cho các đặc tính này "nhìn" như các thành viên bản địa của lớp trang trí miễn là bạn biết các loại việc trang trí trước (hoặc sẵn sàng để trang trí bất kỳ đối tượng):
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);
}
// ...
}
mã của bạn sau đó có thể trông giống như:
DataBag myData = new DataBag();
myData.SetMyDecoratorProperty1(7);
Console.WriteLine("prop1: {0}", myData.GetMyDecoratorProperty1());
thông thường, trang trí tất cả được kế thừa từ một giao diện chung. Trong trường hợp này, giao diện đó sẽ là gì? Nếu nó là năng động, thì có lẽ trang trí không phù hợp. –
Bạn đã xem xét việc có trang trí * kế thừa * từ 'DataBag'? Vấn đề duy nhất là sau đó bạn không thể đúc từ trang trí xuống loại cơ sở. – McGarnagle
@dbaseman Tôi đã sử dụng thừa kế lúc đầu nhưng rất sớm đã đến một tình huống mà rất nhiều lớp học với các thuộc tính hơi khác nhau và phương pháp là cần thiết. – Anton