【发布时间】:2012-04-24 23:44:26
【问题描述】:
在布置类层次结构时,我经常发现自己对能够封装功能和共享代码之间的差距感到沮丧。当然,部分问题是缺乏多重继承,但接口有所帮助。在我看来,无法在接口上定义受保护的方法似乎是更大的问题。
标准的解决方案似乎是有一个由受保护的抽象基类实现的公共接口。问题是当我们有以下情况时
public interface Foo {
public String getName();
}
abstract protected BaseFoo implements Foo {
abstract protected int getId();
private String name;
protected BaseFoo(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
}
public class ConcreteFoo extends BaseFoo {
public ConcreteFoo (String name) {
super(name);
}
@Override
protected int getId() {
return 4; // chosen by fair dice roll.
// guaranteed to be random.
}
}
// in the foo package with the classes above
public class FooCollection {
private static Map<Integer, Foo> foos = new HashMap();
public static void add(Foo foo) {
synchronized(foos) {
foos.put(foo.getId(), foo); // can't call foo.getId()
}
}
}
// client code, not in the foo package
FooCollection.add(new ConcreteFoo("hello world"));
也就是说,我们将一个封装良好的对象返回给调用者,但是任何获取该对象的方法都需要能够依赖一些内部功能。该内部功能不能成为接口的一部分(这会破坏封装),但要使其成为抽象基类的一部分,我们需要使用强制转换。
我们不能使 Foo 成为一个抽象类,因为其他接口需要扩展它以将可选的正交功能添加到比此处显示的更复杂的层次结构中。
解决这个问题的标准方法是什么?您是否将 getId 添加到 Foo 接口,即使客户端不应该使用它?您是否在 FooCollection.add 中对 BaseFoo 执行了不安全的强制转换?如果您在转换前检查,当类型不匹配时,您会怎么做,即使它们始终应符合所有意图和目的?
任何关于这种情况下的最佳实践的信息都会非常有帮助。
编辑:如果不清楚,这个例子是故意过分简化的。关键是有时您会返回对象的“界面视图”。当那个“接口视图”被传回一个包特定的类时,它被传递给的方法可能需要在其实现中使用内部功能。如何管理内部和公共功能之间的不匹配?
【问题讨论】:
-
如果你知道你需要
getId(),那么你有一个ConcreteFoo的集合,而不是Foo。 -
考虑一下:如果 Base implements Foo 会怎样?
-
哎呀,这是一个错字。谢谢
标签: java oop design-patterns interface encapsulation