使用多个装饰器向对象添加功能? [英] Using multiple decorators to add functionality to an object?

查看:163
本文介绍了使用多个装饰器向对象添加功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解装饰器模式,并从示例中我了解了如何使用装饰器对象来在运行时通过重写装饰对象的方法来扩展现有功能,以及如何通过新方法实现来添加附加功能。



我感到有些困惑是使用多个装饰器,以及如何访问扩展功能。通常当查看装饰器模式的示例时,显示如下所示:

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


);

想法是采取一个对象并动态添加邮件,短信和传真功能。
现在,如果你想发送一个MailDecorator类提供的方法的邮件,你可以这样做:

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

但是,如果您要发送短信或传真,装饰器模式的正常实现,您将无法访问装饰器引用的对象。



这是装饰图案的一个限制,还是超出了你可以用这种模式实现的范围,还是我完全误解了这里的东西?

会有不同的模式更合适吗?



标准定义


附加额外的责任为
an动态对象。装饰器

子类提供了一个灵活的替代方案来扩展
功能


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

解决方案

这是一个常见的误解的装饰图案。您可以使用装饰器模式来扩展功能,而不是 API



这是什么意思?

这意味着,您可以添加新功能到API提供的方法,在您的情况下 IBusinessObject 。让我们说你的界面有一个 XmlDocument Export()的方法,它在 BusinessObject 中实现,并返回 BusinessObject XmlDocument 实例中的实例。

现在,您可以创建一个 LoggingDecorator ,它实现 Export 方法,如下所示:

  public XmlDocument Export()
{
_logger.Log(Exporting ...);
var result = _decoratedObject.Export();
_logger.Log(完成导出...);
返回结果;
}

或者您可以创建一个 BusinessObjectSigningExportDecorator 它使用xml-dsig算法来标记返回的 XmlDocument

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

然后,您可以一起使用它们:

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

);

var xmlDocument = businessObject.Export();

调用导出将会写入记录消息并签名xml导出。
但是,您仍然可以使用 BusinessObject 而不使用装饰器,或只能使用其中一个装饰器。



使用装饰器图案的原因是能够透明地添加功能。您可以看到, businessObject 变量类型 IBusinessObject 的用户不知道并且不需要知道使用的实际类型。在有或没有装饰器的情况下,它将工作。



进一步思考:当您有工厂返回 IBusinessObject 时,您可以扩展功能,而无需更改代码它们使用它们,而不会改变实现 IBusinessObject 的类的实现。您只需要创建另一个装饰器,并在工厂内附加,因此您正在进行更改,这种更改仅在代码的有限区域中发生。所以如果这个变化中断了什么,你就会知道什么代码是破坏的。



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


I am trying to understand the decorator pattern and from the examples I understand how decorator objects can be used to extend existing functionality at runtime by overriding methods of the decorated object and how they add additional functionality via new method implementations.

Where I am getting a bit confused is where multiple decorators are used and how to access the extended functionality. Typically when looking at examples of the decorator pattern something like this is shown:

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

the idea being to take an object and dynamically add mail, sms and fax functionaliy. Now if you wanted to send a mail which is a method provided by the MailDecorator class you could do something like this:

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

However this would not work if you wanted to send an SMS or fax as in the normal implementation of the decorator pattern you will not have access to the object referenced by the decorator.

Is this a limitation of the decorator pattern or is it beyond the scope of what you can expect to achieve with this pattern or am I completely misunderstanding something here?
Would a different pattern be more appropriate?

The standard definition

"Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for extending functionality"

implies that this should be achievable with this pattern but appears to break down when using multiple decorators on one object.

解决方案

This is a common misconception of the decorator pattern. What you can do with the decorator pattern is to extend the functionality, not the API.

What does this mean?
It means, you can add new functionality, to the methods provided by the API, in your case IBusinessObject. Lets say your interface has a method XmlDocument Export() which is implemented in BusinessObject and returns the data in the BusinessObject instance in an XmlDocument instance.
Now, you could create a LoggingDecorator, which implements the Export method like so:

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

Or you can create a BusinessObjectSigningExportDecorator which signs the returned XmlDocument using the xml-dsig algorithm:

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

You could then use them together like so:

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

var xmlDocument = businessObject.Export();

The call to Export will now write the log messages and sign the xml export. But you still can use BusinessObject without a decorator or with only one of the decorators.

The reason for using the decorator pattern is to be able to transparently add functionality. As you can see, the user of the businessObject variable of type IBusinessObject doesn't know and doesn't need to know the actual type that is used. It will work in the case with or without decorators.

Thinking further: When you have a factory that returns IBusinessObjects you can extend the functionality, without changing the code that uses them and without changing the implementation of the class the implement IBusinessObject. You just need to create another decorator and "attach" it inside the factory and therefore, you are making a change, that occurs only in a limited area of the code. So if this change breaks anything, you know exactly what code is responsible for the breakage.

Additionally, this enforces separation of concerns, because your normal business object implementation doesn't know and care about which signing algorithm should be used or that one needs to be used altogether.

这篇关于使用多个装饰器向对象添加功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆