使用多个装饰器向对象添加功能?
我试图理解装饰器模式,并从示例中了解装饰器对象如何通过重写装饰对象的方法来在运行时扩展现有功能,以及它们如何通过新方法实现添加附加功能。
我有点困惑的是在哪里使用多个装饰器以及如何访问扩展功能。通常,当查看装饰器模式的示例时,会显示如下内容:
IBusinessObject businessObject = new MailDecorator(
new SmsDecorator(
new FaxDecorator(
new BusinessObject()
)
)
);
其想法是采用一个对象并动态添加邮件、短信和传真功能。 现在,如果您想发送邮件(这是 MailDecorator 类提供的方法),您可以执行以下操作:
If(businessObject is MailDecorator)
{
((MailDecorator) businessObject).SendMail();
}
但是,如果您想发送 SMS 或传真,则这将不起作用,就像装饰器模式的正常实现一样,您不会这样做可以访问装饰器引用的对象。
这是装饰器模式的限制还是超出了您期望使用此模式实现的范围,或者我完全误解了这里的某些内容?
不同的模式会更合适吗?
标准定义
“附加额外的责任 一个动态的对象。装饰器 提供灵活的替代方案 用于扩展的子类 功能”
意味着这应该可以通过此模式实现,但在一个对象上使用多个装饰器时似乎会崩溃。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是对装饰器模式的常见误解。使用装饰器模式可以做的是扩展功能,而不是API。
这是什么意思?
这意味着,您可以向 API 提供的方法(在您的情况下为
IBusinessObject
)添加新功能。假设您的接口有一个方法XmlDocument Export()
,该方法在BusinessObject
中实现,并返回BusinessObject
实例中的数据。 XmlDocument 实例。现在,您可以创建一个
LoggingDecorator
,它实现Export
方法,如下所示:或者您可以创建一个
BusinessObjectSigningExportDecorator
来对返回的进行签名使用 xml-dsig 算法的 XmlDocument
:然后您可以像这样一起使用它们:
对
Export
的调用现在将写入日志消息并签署 xml 导出。但您仍然可以在没有装饰器或仅使用其中一个装饰器的情况下使用 BusinessObject。
使用装饰器模式的原因是能够透明地添加功能。正如您所看到的,
IBusinessObject
类型的businessObject
变量的用户不知道也不需要知道所使用的实际类型。无论有没有装饰器,它都可以工作。进一步思考:当您有一个返回
IBusinessObject
的工厂时,您可以扩展功能,而无需更改使用它们的代码和,而无需更改实现类的实现<代码>IBusinessObject。您只需要创建另一个装饰器并将其“附加”到工厂内,因此,您所做的更改仅发生在代码的有限区域中。因此,如果此更改破坏了任何内容,您就可以确切地知道哪些代码导致了破坏。此外,这强制了关注点分离,因为您的正常业务对象实现不知道也不关心应该使用哪种签名算法或者需要一起使用哪种签名算法。
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 methodXmlDocument Export()
which is implemented inBusinessObject
and returns the data in theBusinessObject
instance in anXmlDocument
instance.Now, you could create a
LoggingDecorator
, which implements theExport
method like so:Or you can create a
BusinessObjectSigningExportDecorator
which signs the returnedXmlDocument
using the xml-dsig algorithm:You could then use them together like so:
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 typeIBusinessObject
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
IBusinessObject
s you can extend the functionality, without changing the code that uses them and without changing the implementation of the class the implementIBusinessObject
. 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.