使用多个装饰器为对象添加功能?

时间:2011-04-05 11:24:27

标签: c# design-patterns decorator

我正在尝试理解装饰器模式,并且从示例中我理解装饰器对象如何通过覆盖装饰对象的方法以及它们如何通过新方法实现添加其他功能来在运行时扩展现有功能。

我感到有点困惑的地方是使用多个装饰器以及如何访问扩展功能。通常,在查看装饰器模式的示例时,会显示以下内容:

IBusinessObject businessObject = new MailDecorator(
    new SmsDecorator(
        new FaxDecorator(
            new BusinessObject()
        )
    )
);

的想法是获取一个对象并动态添加邮件,短信和传真功能。 现在,如果您想发送邮件,这是MailDecorator类提供的方法,您可以执行以下操作:

If(businessObject is MailDecorator)
{
    ((MailDecorator) businessObject).SendMail();
}  

但是,如果您想要发送短信或传真,就像在装饰器模式的正常实现中那样,您将无法访问装饰器引用的对象,这将无效。

这是装饰器模式的限制还是超出了你可以期望用这种模式实现的范围,还是我在这里完全误解了什么?
不同的模式会更合适吗?

标准定义

  

“将附加职责附加到   一个动态的对象。装饰   提供灵活的替代方案   用于扩展的子类   功能”

暗示这应该可以通过这种模式实现,但在一个对象上使用多个装饰器时似乎会崩溃。

1 个答案:

答案 0 :(得分:15)

这是装饰者模式的常见误解。您可以使用装饰器模式执行的操作是扩展功能,而不是 API

这是什么意思?
这意味着,您可以在案例IBusinessObject中为API提供的方法添加新功能。假设您的接口有XmlDocument Export()方法,该方法在BusinessObject中实现,并返回BusinessObject实例中XmlDocument实例中的数据。
现在,您可以创建一个LoggingDecorator,它实现Export方法,如下所示:

public XmlDocument Export()
{
    _logger.Log("Exporting...");
    var result = _decoratedObject.Export();
    _logger.Log("Done exporting...");
    return result;
}

或者您可以创建一个BusinessObjectSigningExportDecorator,使用xml-dsig算法对返回的XmlDocument进行签名:

public XmlDocument Export()
{
    var result = _decoratedObject.Export();
    return SignXmlDocument(result);
}

然后您可以像这样一起使用它们:

IBusinessObject businessObject = new LoggingDecorator(
    new BusinessObjectSigningExportDecorator(
        new BusinessObject()
    )
);

var xmlDocument = businessObject.Export();

Export的调用现在将写入日志消息并签署xml导出。 但是你仍然可以在没有装饰器的情况下使用BusinessObject,或者只使用其中一个装饰器。

使用装饰器模式的原因是能够透明地添加功能。如您所见,businessObject类型IBusinessObject变量的用户不知道也不需要知道所使用的实际类型。它适用于有或没有装饰器的情况。

进一步思考:如果您有一个返回IBusinessObject的工厂,您可以扩展功能,而无需更改使用它们的代码,而无需更改实现类的实现{ {1}}。您只需要创建另一个装饰器并在工厂内“附加”它,因此,您正在进行更改,这只发生在代码的有限区域。因此,如果此更改破坏了任何内容,则您确切知道哪些代码会导致破坏。

此外,这会强制关注点分离,因为您的正常业务对象实现不知道并关心应该使用哪种签名算法,或者需要完全使用哪种签名算法。