A recent article described some problems when dealing with Java interfaces, coming from a language that allows duck typing.
底线是这个。 有一个接口:
public interface DynamoImpl {
public PutItemResult putItem(PutItemRequest putItemRequest);
public GetItemResult getItem(GetItemRequest getItemRequest);
}
还有一堂课亚马逊DynamoDB。 该类具有上述两种方法,但还有更多方法。 现在,程序员John要只公开这两种方法亚马逊DynamoDB到他的程序的其余部分。 他想在课堂上使用它们数据库:
public class Database {
public DynamoImpl db;
// code removed for simplicity
public Database(DynamoImpl db) {
this.db = db;
}
}
现在:使用支持鸭子输入的语言,您只需传递类的实例亚马逊DynamoDB到构造函数,并调用两个方法(因为该类具有它们)。但是,不是在Java中。您需要传入一个类的实例从字面上看实施theDynamoImplinterface(orextendsaclassthatdoesso).But亚马逊DynamoDBdoesnotimplementthatinterface.
在Java中实现相同目标的最简单方法是创建一个包装,将其委托给亚马逊DynamoDB实例:
public class AmazonDynamoDbWrapper implements DynamoImpl{
private AmazonDynamoDB amazonDynamoDB;
public AmazonDynamoDbWrapper(AmazonDynamoDB amazonDynamoDB) {
this.amazonDynamoDB = amazonDynamoDB;
}
@Override
public PutItemResult putItem(PutItemRequest putItemRequest) {
return amazonDynamoDB.putItem(putItemRequest);
}
@Override
public GetItemResult getItem(GetItemRequest getItemRequest) {
return amazonDynamoDB.getItem(getItemRequest);
}
}
是的,有点冗长,但是一旦您理解了模式,就可以很直接地进行。 现在您可以将此类的实例传递给的实例数据库。
生产代码就这么多。 那测试呢?
最简单的解决方案是提供DynamoImpl界面,如下所示:
public class StubbedDynamoImpl implements DynamoImpl {
@Override
public PutItemResult putItem(PutItemRequest putItemRequest) {
return new PutItemResult(/* Test data here */);
}
@Override
public GetItemResult getItem(GetItemRequest getItemRequest) {
return new GetItemResult(/* Test data here */);
}
}
同样,您可以将此类的实例传递给数据库实例的构造函数,在测试中:
public class DatabaseTest {
@Test
public void createsDatabase() {
Database database = new Database(new StubbedDynamoImpl());
// Whatever your test assertions are, here
}
// ...
}
如果您只想公开两种方法,则无需花哨的模拟框架。 这是我能想到的最简单的解决方案。 我希望它有用。
附言 关于Java约定的一句话:请不要对接口使用后缀Impl。 这应该用于具体的实现类(如果有的话),否则可能会使很多人感到困惑。