在将公共API转换为内部粘合代码时避免强制转换

时间:2009-08-07 14:38:47

标签: java oop encapsulation

所以,我有我的应用程序公开的这个公共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。

有人能想到更聪明的事吗?

2 个答案:

答案 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); } } 上公开方法(至少通过接口)以允许访问者实现调用它们。但是,您仍然可以在包级别保留实现细节。