有效地使用Decorator模式

本文关键字:模式 Decorator 有效地 | 更新日期: 2023-09-27 18:17:32

我正在设计一个库,提供对我们公司使用的Bug Tracker应用程序的访问。

目前,我们只需要访问简单的函数:

    <
  1. 打开缺陷/gh>
  2. 查询缺陷(按给定条件搜索)
  3. 连接/断开Bug跟踪器

我设计这个库是为了提供这些操作的接口,这样我们就可以在新版本出现时透明地替换实现。

为了支持将来更多的操作,我们可以:

  1. 展开接口;使所有实现类实现添加的成员。
  2. 使用Decorator模式在运行时添加操作/功能。

问题是——Decorator似乎过于依赖于底层基类/接口。我的意思是,它依赖于这样一个事实:它所修饰的对象提供了足够的访问,使它能够轻松地添加操作。

在这个例子中,如果我没有在我的接口中公开为bug跟踪器提供API的底层第三方对象,那么decorator将无法添加更多的操作。

我如何通过更好的设计来克服这个问题?

有效地使用Decorator模式

你不需要Decorator模式

装饰器模式在这个场景中不是很有用。它的目的是允许您在运行时附加行为。您试图在编译时(或多或少)附加行为

见:http://en.wikipedia.org/wiki/Decorator_pattern

此模式允许用户创建以下类型的代码实例:

  • 故意未修饰的类型,只有基本行为
  • 允许您提供覆盖行为的任意装饰类型

要做到这一点,它会产生大量的设计开销。对于一个装饰,你需要实现四个类。

如果你不关心实例化故意未修饰的类型,这是一个很大的开销。

你可能根本不需要担心这个

我只会担心这种情况,如果您已经推出了一个接口,并且一次重新部署所有内容(客户端和服务)将是昂贵的。如果你有能力一次为所有用户重新部署整个世界,那就修改界面吧。

多个接口更适合您的场景

如果你只是想保持你的服务和客户端运行,而做交错的推出,我建议你利用。net允许接口的多重继承,并版本你的接口。

发布修改接口的新版本时,添加一个新接口并同时实现这两个接口。让你的对象实现这两个接口。

这将允许您错开部署并保持向后兼容。您可以在任何时间对您的日程安排最有意义时弃用和删除旧接口。

这里有一个例子。请注意,除了解决您的特定问题外,我根本没有考虑服务的设计:

namespace Version1
{
    public interface IOpenDefectService
    {
        void Submit(string title, string description, int severity);
        void Bump(int issueId);
    }
}
namespace Version2
{
    public interface IOpenDefectService
    {
        void Submit(string title, string description, int severity);
        // Removed Bump method - it was a bad idea
        // Added an optional priority field
        void Submit(string title, string description, int severity,
            int priority);
        // Added support for deleting 
        void Delete(int id);
    }
}
public class OpenDefectService : Version1.IOpenDefectService,
    Version2.IOpenDefectService
{
    // Still must support it until you no longer have any clients using it.
    // Here to support staggered rollouts
    [Obsolete("This method is deprecated.  Don't use it")]
    public void Bump(int issueId) { /* Still has implementation... */ }
    public void Submit(string title, string description,
        int severity) { /* ... */ }
    public void Submit(string title, string description,
        int severity, int priority) { /* ... */ }
    public void Delete(int id) { /* ... */ }
}