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

And*_*ose 6 c# design-patterns decorator

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

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

IBusinessObject businessObject = new MailDecorator(
    new SmsDecorator(
        new FaxDecorator(
            new BusinessObject()
        )
    )
);
Run Code Online (Sandbox Code Playgroud)

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

If(businessObject is MailDecorator)
{
    ((MailDecorator) businessObject).SendMail();
}  
Run Code Online (Sandbox Code Playgroud)

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

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

标准定义

"动态地将附加职责附加到对象.装饰器为子类提供了灵活的替代方案,可以扩展功能"

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

Dan*_*rth 15

这是装饰器模式的常见误解.你可以用装饰器模式做的是扩展功能,而不是API.

这是什么意思?
这意味着,在您的情况下,您可以向API提供的方法添加新功能IBusinessObject.假设您的接口有一个XmlDocument Export()实现的方法,BusinessObject并在BusinessObject实例中返回实例中的数据XmlDocument.
现在,你可以创建一个LoggingDecorator,它实现了Export这样的方法:

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

或者您可以使用xml-dsig算法创建一个BusinessObjectSigningExportDecorator对返回XmlDocument的符号:

public XmlDocument Export()
{
    var result = _decoratedObject.Export();
    return SignXmlDocument(result);
}
Run Code Online (Sandbox Code Playgroud)

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

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

var xmlDocument = businessObject.Export();
Run Code Online (Sandbox Code Playgroud)

现在调用Export将写入日志消息并签署xml导出.但你仍然可以使用BusinessObject没有装饰器或只有一个装饰器.

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

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

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