32

例如,我一直在尝试使用装饰器模式来扩展您不想接触的代码的功能,并且我看到了如何实现它,但是我现在不确定为什么您不只是从原始类继承并以这种方式进行扩展。

我读过装饰器模式允许您在运行时添加功能,而继承意味着它在编译时就在那里。

我不明白这一点。

有人可以解释一下,提供示例并解释何时使用装饰器与继承更好。

谢谢

4

4 回答 4

33

假设您创建了一个 View 类,以某种方式显示您的项目。现在你决定你还想要一个可滚动的版本,所以你创建了一个继承 View 的 ScrollableView。后来你决定你也想要一个有边框的版本,所以你现在需要制作一个 BorderedView 和一个 BorderdScrollableView。

另一方面,如果您可以为每个添加的样式制作一个装饰器。您将有以下课程:

  • 看法
  • 可滚动装饰器
  • 边框装饰器

当您想要一个有边框的滚动视图时,您可以:

new BorderedDecorator(new ScrollableDecorator(new View())).

因此,您可以仅使用 3 个类来配置任何组合。而且您可以在运行时添加或删除它们(假设您单击一个显示添加边框的按钮,您现在用 BorderDecorator 包装您的视图......而如果您还没有继承,您需要实现这个视图类,或者您需要创建一个新的视图实例并将所有相关数据从第一个视图复制到第二个视图,这不像添加或删除包装器那么容易)。

于 2012-07-26T11:29:26.757 回答
30

想象一个像文明这样的游戏,地图上的每个方格都可以附有各种资源(例如,各种矿石、木材或石油等)。

如果您使用直接继承,则需要为每种正方形创建一个类。拥有它会很笨拙

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

换句话说,装饰器允许创建管道行为,管道中的每个步骤都可以与另一个步骤交换。

于 2012-07-26T11:28:59.603 回答
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),因此它们不应该公开任何新方法或属性,只是稍微改变现有方法或属性的效果。

于 2012-07-26T11:45:16.930 回答
7

如果您要添加许多功能并且还需要组合这些功能,则装饰器模式比继承更好。假设您的基类是 A,并且您想扩展(装饰)这个基类,其特征是 f1,f2,f3,f4 以及它们的某种组合,例如 (f1,f2) 和 (f1,f3) 和 ..;所以你需要在你的层次结构中创建 4!=4*3*2*1=24 类(每个特征 4 个,其余的用于它们的组合)。而使用装饰图案,您只需要创建 4 个类!


对于@Razvi 帖子中的@Seyed Morteza Mousavi:你是对的,我们可以将两个属性 Scrollable 和 Bordered 添加到 View 类,然后检查该属性是否设置为 true 以便运行所需的行为。但这要求我们已经知道我们需要的功能的数量(装饰器模式不是这种情况)。否则,对于我们想要添加到我们的类的每个新特性(比如 f1),我们需要更改我们的主类,或者继承主类(你会说)并添加属性。采用后一种方法,您将进一步需要更改处理功能组合的代码部分(这不好,因为它不遵守“松散耦合!”的经验法则)

希望这可以帮助。

于 2014-01-27T21:38:59.057 回答