所以,我有我的应用程序公开的这个公共API,允许客户编写插件。为了这个例子,让我们说它是一个相当简单的键值对系统,如:
public interface Key {
// marker interface, guaranteed unique in some scope
}
public interface KVPService {
Set<Key> getKeys();
Object getValue(Key k); // must be a key provided by getKeys() or it blows up
}
现在让我们说在内部,Key
有一些不应该公开的属性 - 比如数据库ID。我目前正在做的是这样的事情:
/** Internal impl of external Key */
class InternalKey implements Key {
int getDatabaseId() {
// do something...
}
}
/** Internal impl of external KVPService */
class InternalKVPService implements KVPService {
// ...
public Object getValue(Key k) {
InternalKey ik = (InternalKey) k;
return getValueFromDBOrWherever(ik.getDatabaseId());
}
// ...
}
这似乎不太理想。有没有什么方法可以重新安排责任以避免演员表并仍然保持内部/外部封装?
请注意,在现实世界中,它比这更复杂; Key
等价物附加了相当多的元数据,并且除了获得一个简单的值之外,还有许多人可能想要做的事情,所以只需公开Map.Entry
- 像对象一样赢了't 必然解决问题。
我唯一能想到的就是完全分开内部和外部密钥,并保持Map<Key, InternalKey>
。但在这种情况下,我必须复制违反DRY的元数据,或者将Key
委托给InternalKey
,在这种情况下,Map
会违反DRY。
有人能想到更聪明的事吗?
答案 0 :(得分:1)
我不这么认为。但为什么类型转换会让你担心呢?潜在的ClassCastException在实践中不会发生(假设我理解你的用例),强制转换只需要5个左右的机器指令,并且它对你的KPService API的调用者是隐藏的。
答案 1 :(得分:1)
我看到的一种方法是为所有对象(在本例中为键)公开一个公共接口,并提供一个基本实现,它只是为每个方法抛出UnsupportedOperationException
(或什么都不做)。然后,子类实现覆盖方法以提供功能。虽然它不像OO,但你会在JDK API中找到一些例子(例如Iterator
的{{1}}方法)。
另一种选择:您可以使用visitor模式让每个对象执行功能而无需向下转换; e.g。
remove()
这里的缺点是您必须在public interface KeyVisitor {
void visitInternalKey(InternalKey k);
void visitFooBarKey(FooBarKey k);
}
public interface Key {
void visit(KeyVisitor kv);
}
public class InternalKey implements Key {
public void visit(KeyVisitor kv) {
kv.visitInternalKey(this);
}
}
上公开方法(至少通过接口)以允许访问者实现调用它们。但是,您仍然可以在包级别保留实现细节。