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

发布于 2024-10-30 14:01:09 字数 800 浏览 0 评论 0原文

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

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

忘年祭陌 2024-11-06 14:01:09

这是对装饰器模式的常见误解。使用装饰器模式可以做的是扩展功能,而不是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;
}

或者您可以创建一个 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。

使用装饰器模式的原因是能够透明地添加功能。正如您所看到的,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 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文