界面不断变化的装饰器模式

时间:2019-02-21 10:31:12

标签: java database oop design-patterns

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

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);
    }
} 

只要Database接口不引入新方法,此方法就可以正常工作,但是只要它们开始添加我并不真正在意的API,例如删除/ getDBInfo / deleteDB等问题开始出现。

每当发布具有较新方法的DB新版本时,我对RateLimitedDatabase的构建都会中断。一个选项是在装饰类中实施新方法,以调查构建失败的根本原因,但这对开发人员而言是额外的痛苦。还有其他方法可以处理此类情况,因为在将Decorator模式与不断变化/扩展的接口配合使用时,这似乎是一个常见问题?

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

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:0)

面向方面的编程可以解决此问题。 大多数框架都会为您的界面生成一个动态代理,因此它总是同步的。