装饰模式与不断变化的接口

问题描述 投票:1回答:2

我有一个用例,我有一个由外部供应商提供的数据库接口,让我们说它看起来如下:

interface Database{

   public Value get(Key key);

   public void put(Key key, Value value)

}

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

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的构建将会中断。一个选项是在装饰类中实现新方法,以研究构建失败的根本原因,但这对开发人员来说只是一个额外的痛苦。有没有其他方法来处理这种情况,因为当使用具有不断变化/扩展的接口的Decorator模式时,这似乎是一个常见的问题?

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

java database oop design-patterns
2个回答
1
投票

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

编辑客户端代码以使用mirror.Database接口,让RateLimitedDatabase实现此mirror.Database接口。由于所有方法签名都相同,因此将客户端代码切换到镜像接口应该是无痛的。当然,RateLimitedDatabase将委托给vendor.Database实施。

(我认为我所描述的或多或少是桥模式(使用界面“屏蔽”潜在的变化),https://en.wikipedia.org/wiki/Bridge_pattern


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.