【发布时间】:2010-05-08 14:40:34
【问题描述】:
这更像是一个设计问题......如果:
1) 该对象被标记为“密封”,这意味着您不能从它扩展。 2) 或者你想覆盖一个方法,但它不是虚拟的。
那你能做什么?如果您没有源代码(如第 3 方库),则无法更改类源代码。
【问题讨论】:
标签: c#
这更像是一个设计问题......如果:
1) 该对象被标记为“密封”,这意味着您不能从它扩展。 2) 或者你想覆盖一个方法,但它不是虚拟的。
那你能做什么?如果您没有源代码(如第 3 方库),则无法更改类源代码。
【问题讨论】:
标签: c#
装饰器模式不需要继承。最简单的情况是,如果您要装饰的对象实现了一个接口。然后你的装饰器可以简单地实现相同的接口:
[ IWindow ]
[ + Draw() ]
---------------
|
+--- [ Window ]
| [ + Draw() ]
|
|
+--- [ DecoratedWindow ]
[ + Draw() ]
-------------------
|
+--- [ BorderDecorator ]
|
+--- [ VerticalScrollbarDecorator ]
|
+--- [ HorizontalScrollbarDecorator ]
现在你可以这样做了:
IWindow w = new BorderDecorator(
new HorizontalScrollBarDecorator(
new VerticalScrollBarDecorator(
new Window(80, 24))));
// This is a window with a border and scrollbars, even though
// the original Window class has no idea what those are.
w.Draw();
可能的细节取决于您尝试装饰的类的确切性质。
【讨论】:
您可以采取多种方法,具体取决于您对代码的实际控制程度:
1) 您是否将密封类的实例传递给第三方代码?如果是这样,除了祈祷您的第三方接受接口而不是具体对象之外,您无能为力。
完全可以在 CLR 中编写钩子来拦截密封类中的方法,这就是一些模拟框架如何模拟非虚拟方法和密封类的方式。我不建议这样做,因为您的第三方代码是针对对象的特定实现编写的,并且在第三方代码的鼻子下换出实现可能会产生不平凡的、未定义的后果。
2) 您是否在自己的代码中使用密封类?如果是这样,那就去小工具包装吧!使用与您的密封类相同的公共方法创建一个非密封类,公共方法应该传递给您的密封对象,然后您可以根据需要覆盖您的类的功能。
3) 您是否拥有密封类的代码?如果是这样,请找到类定义,双击“密封”关键字以突出显示它,根据需要按删除键;)或者可能将接受密封对象的方法换成具有相同公共方法的接口。
【讨论】:
您可以创建自己的类来包装第 3 方类并装饰该类。您的类将使用包装类实现。包装类充当适配器。
【讨论】:
如果您不能继承并且原始类没有实现您也可以在装饰器上实现的任何接口,那么我相信您应该尝试代理类或适配器。如果这也不可能,那么你总是有一个“替代技术资源”:你可以定义一个 conversion operator 允许将你的装饰器转换为原来的装饰器(尽管我认为这不是一个很好的选择)。
【讨论】: