【问题标题】:Decorator Pattern with ever changing interfaces具有不断变化的界面的装饰器模式
【发布时间】:2019-02-21 10:31:11
【问题描述】:

我有一个用例,我有一个由外部供应商提供的数据库接口,假设它如下所示:

interface Database{

   public Value get(Key key);

   public void put(Key key, Value value)

}

供应商提供了此接口的多种实现,例如ActualDatabaseImpl,MockDatabaseImpl。我的消费者想要使用 DataBase 接口,但在调用某些 API 之前,他们想要执行一些额外的工作,例如在调用之前调用客户端速率限制器。因此,与其让每个消费者都必须做额外的检查 rateLimiter 限制的工作,我想创建一个装饰类,它将抽象出速率限制部分,并且消费者可以在不知道 RateLimiter 逻辑的情况下与 DB 交互。例如

class RateLimitedDatabase implements Database{

    private Database db;
    public RateLimitedDatabase(Database db) {this.db = db;}

    public Value get(Key key) { 
          Ratelimiter.waitOrNoop();
          return db.get(key);
    }

    public void put(Key key, Value value) {
         Ratelimiter.waitOrNoop();
         return db.put(key, value);
    }
} 

只要数据库接口不引入新方法,这工作正常。但是一旦他们开始添加我并不真正关心的 API,例如delete/getDBInfo/deleteDB 等问题开始出现。

每当发布具有更新方法的新版本 DB 时,我的 RateLimitedDatabase 构建就会中断。一种选择是在装饰类中实现新方法以调查构建失败的根本原因,但这对开发人员来说只是额外的痛苦。有没有其他方法来处理这种情况,因为这似乎是使用带有不断变化/扩展接口的装饰器模式时的常见问题?

注意:我也可以考虑构建一个基于反射的解决方案,但这似乎是针对这个特定问题的过度杀伤/过度工程。

【问题讨论】:

    标签: java database oop design-patterns


    【解决方案1】:

    如果可行(您需要修改所有客户端代码),您可以提取vendor.Database 接口的“镜像”并调用它,例如。 mirror.Database;并将您需要的方法从vendor.Database 接口复制到mirror.Database(具有完全相同的签名)。

    编辑客户端代码使用mirror.Database接口,让RateLimitedDatabase实现这个mirror.Database接口。由于所有方法签名都相同,因此将客户端代码切换到镜像接口应该很容易。 RateLimitedDatabase 当然会委托给 vendor.Database 实现。

    (我认为我所描述的或多或少是桥接模式(使用接口来“屏蔽”底层变化),https://en.wikipedia.org/wiki/Bridge_pattern

    【讨论】:

      【解决方案2】:

      面向方面的编程有解决这个问题的方法。 大多数框架都会为您的界面生成动态代理,因此它始终保持同步。

      【讨论】:

        猜你喜欢
        • 2021-11-24
        • 1970-01-01
        • 1970-01-01
        • 2016-10-14
        • 2018-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-08
        相关资源
        最近更新 更多