我一直在尝试使用装饰器模式来扩展你不想触摸的代码的功能,我看到了如何实现它但是我现在不确定你为什么不继承原始类并扩展那样。
我已经读过装饰器模式允许你在运行时添加功能,而继承意味着它在编译时。
我不明白这一点。
有人可以解释一下,提供示例并解释何时使用装饰器与继承更好。
由于
答案 0 :(得分:31)
假设您创建了一个以特定方式显示项目的View类。 现在您决定还需要一个可滚动的版本,因此您创建了一个继承View的ScrollableView。 稍后您决定还需要带边框的版本,因此您现在需要创建BorderedView和BorderdScrollableView。
如果另一方面,你可以为每个添加的样式制作装饰器。您将拥有以下课程:
如果需要带边框的滚动视图,请执行以下操作:
new BorderedDecorator(new ScrollableDecorator(new View()))
。
所以你可以用3个类来配置它的任意组合。你可以在运行时添加或删除它们(假设你单击一个添加边框的按钮,你现在用BorderDecorator包装你的视图......你需要实现这个视图类,如果你还没有,或者你需要创建一个新的视图实例并将所有相关数据从第一个视图复制到第二个视图,这不像添加或删除包装器那样容易。
答案 1 :(得分:27)
想象一下像“文明”这样的游戏,地图上的每个方格都可以附加各种资源(例如,各种矿石,木材或石油等)。
如果您使用直接继承,则需要为每种方块创建一个类。
是不实用的public class OilSquare {}
public class OilAndGoldSquare {}
public class GoldAndSilverSquare {}
// etc.
装饰器模式允许混合和匹配,而无需创建严格的层次结构。所以,你改为:
public class Square {}
public class GoldDec {}
public class SilverDec {}
public class OilDec {}
// ...
var crazyMix = new GoldDec(new SilverDec(new OilDec(new Square())));
换句话说,装饰器允许创建管道行为,管道中的每个步骤都可以用另一个步骤进行交换。
答案 2 :(得分:13)
正如其他人已经说过装饰器有助于为事物添加“选项”......好处来自于你可以通过装饰器链接方法等。
想象一下,我买的车有皮革内饰,金属漆和令人敬畏的扰流板......
这三个选项有8种不同的组合,但是装饰器只需要三个额外的类。
有趣的是装饰图案的工作方式。作为一个简短的例子:
public class MetallicPaint : Car
{
private Car car;
public MetallicPaint(Car wrappedCar)
{
car = wrappedCar;
}
public decimal Cost()
{
return car.Cost() + 500;
}
public string Description()
{
return car.Description() + ", Metallic Paint";
}
public string Speed()
{
return car.Speed();
}
[... {pass through other methods and properties to the car object}]
}
这不是一个完整的例子,但强调了装饰者如何与正在装饰的对象进行交互。当然,因为它可以实现汽车,所以它可以像其他任何方式一样使用汽车(并且通过任何装饰器不会对内部汽车对象产生影响)。
当然,如果你有多个这些装饰器,其中一个嵌套在里面的汽车将反过来增加他们的成本,他们的部分描述和扰流板会改变速度,而其他人没有......
本质上,它允许您以比继承更加模块化和不太基本的方式修改对象。装饰器应该总是像它们是基础对象一样使用(在本例中为Car
),因此它们不应该暴露任何新方法或属性,只需稍微改变现有方法或属性的效果。
答案 3 :(得分:6)
如果要添加许多功能并且还需要组合这些功能,装饰器模式优于继承。假设您的基类是A,并且您希望使用特征f1,f2,f3,f4以及它们的某些组合(如(f1,f2)和(f1,f3)和...)扩展(修饰)此基类。因此,您需要在层次结构中创建4!= 4 * 3 * 2 * 1 = 24类(每个功能4个,其余为其组合)。而使用装饰图案,你只需要创建4个类!