3

因此,我的应用程序公开了这个公共 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的对象并不一定能解决问题。

我唯一能想到的就是将内部和外部键完全分开,并保留一个Map<Key, InternalKey>. 但在那种情况下,我必须复制违反 DRY 的元数据,或者让外部Key委托到InternalKey,在这种情况下Map违反 DRY。

谁能想到更聪明的方法?

4

2 回答 2

1

我不这么认为。但是为什么类型转换会让你担心呢?潜在的 ClassCastException 在实践中不会发生(假设我了解您的用例),转换只需要 5 个左右的机器指令,并且它对您的 KPService API 的调用者是隐藏的。

于 2009-08-07T14:52:03.547 回答
1

我见过的一种方法是为所有对象(在本例中为键)公开一个公共接口,并提供一个基本实现,它UnsupportedOperationException为每个方法简单地抛出一个(或什么都不做)。然后子类实现随后覆盖方法以提供功能。当然,它不是很像 OO,但您会在 JDK API 中找到一些示例(例如Iterator'sremove()方法)。

另一种选择:您可以使用访问者模式让每个对象执行功能而无需向下转换;例如

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);
  }
}

这里的缺点是您必须公开InternalKey(至少通过接口)上的方法以允许您的访问者实现调用它们。但是,您仍然可以将实现细节保留在包级别。

于 2009-08-07T14:52:45.150 回答