在布置类层次结构时,我经常发现自己能够封装功能并共享代码之间存在差距。当然,部分问题是缺乏多重继承,但接口有所帮助。在界面上无法定义受保护的方法在我看来是更大的问题。正确设计用于代码共享和封装的Java类层次结构
标准解决方案似乎是通过受保护的抽象基类实现的公共接口。问题是,当我们有以下
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'。 – jpm 2012-04-24 23:55:22
考虑:如果Base *实现* Foo会怎么样? – 2012-04-25 00:00:42
哎呀,那是一个错字。谢谢 – 2012-04-25 00:06:28