I have a use case where I have a Database interface vended by an external vendor let's say it looks like following:
interface Database{
public Value get(Key key);
public void put(Key key, Value value)
}
The vendor provides multiple implementations of this interface e.g. ActualDatabaseImpl, MockDatabaseImpl. My consumers want to consume DataBase interface but before calling some of the APIs they want to perform some additional work e.g Call client side rate limiter before making call. So rather than every consumer having to do the extra work of checking rateLimiter's limit, I thought of creating a decorated class which will abstract out the rate limit part and consumers can interact with DB without knowing the logic of RateLimiter. e.g.
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);
}
}
This works fine as long as the Database interface doesn't introduce new methods.But as soon as they start adding APIs that I don't really care about e.g. delete/getDBInfo/deleteDB etc problems start arising.
Whenever a new version of DB with newer methods is released my build for RateLimitedDatabase will break.One option is to implement the new methods in the decorated class on investigating the root cause for build failure but that's just an extra pain for developers. Is there any other way to deal with such cases since this seems to be a common problem when using Decorator pattern with an ever changing/extending interface?
NOTE: I can also think of building a reflection based solution but that seems to be an overkill/over-engineering for this particular problem.
Aucun commentaire:
Enregistrer un commentaire