Шаблон Decorator с постоянно меняющимися интерфейсами - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть случай использования, когда у меня есть интерфейс базы данных, предоставленный внешним поставщиком, скажем, он выглядит следующим образом:

interface Database{

   public Value get(Key key);

   public void put(Key key, Value value)

}

Поставщик предоставляет несколько реализаций этого интерфейса, например ActualDatabaseImpl, MockDatabaseImpl.Мои потребители хотят использовать интерфейс DataBase, но перед вызовом некоторых API они хотят выполнить некоторую дополнительную работу, например, ограничить скорость на стороне клиента перед выполнением вызова.Поэтому вместо того, чтобы каждый потребитель мог выполнять дополнительную работу по проверке лимита rateLimiter, я подумал о создании декорированного класса, который будет абстрагировать часть ограничения скорости, и потребители смогут взаимодействовать с БД, не зная логику 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, которые меня не особо волнуют, например, проблемы удаления / getDBInfo / deleteDB и т. д.начало возникать.

Всякий раз, когда выпускается новая версия БД с более новыми методами, моя сборка для RateLimitedDatabase ломается. Один из вариантов - реализовать новые методы в украшенном классе при исследовании первопричины сбоя сборки, но это простодополнительная боль для разработчиков.Есть ли другой способ справиться с такими случаями, так как это кажется распространенной проблемой при использовании шаблона Decorator с постоянно меняющимся / расширяющимся интерфейсом?

ПРИМЕЧАНИЕ. Я также могу подумать о создании решения на основе отражения, но этопохоже, это излишнее / чрезмерное решение этой конкретной проблемы.

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Аспектно-ориентированное программирование имеет решение этой проблемы.Большинство фреймворков генерируют динамический прокси для вашего интерфейса, поэтому он всегда синхронизирован.

0 голосов
/ 21 февраля 2019

Если это возможно (вам нужно изменить весь свой клиентский код), вы можете извлечь «зеркало» интерфейса vendor.Database и вызвать его, например.mirror.Database;и скопируйте только те методы, которые вам нужны, из интерфейса vendor.Database в mirror.Database (с теми же сигнатурами).

Отредактируйте код клиента, чтобы использовать интерфейс mirror.Database, и позвольте RateLimitedDatabase реализоватьэтот mirror.Database интерфейс.Поскольку все сигнатуры методов одинаковы, переключение клиентского кода на зеркальный интерфейс должно быть безболезненным.RateLimitedDatabase делегирует, конечно, vendor.Database реализацию.

(я думаю, что я описал более или менее паттерн моста (используя интерфейс для «защиты» от базовых изменений), https://en.wikipedia.org/wiki/Bridge_pattern)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...