我在抽象类中有一个方法,它调用一个抽象方法,子类必须为其提供实现。
public abstract class AClass {
public void foo() {
...
fooToImplement();
...
}
// DON'T CALL THIS METHOD, ONLY PROVIDE IMPLEMENTATION!
protected abstract void fooToImplement();
}
我想确保子类不调用fooToImplement(),它们应该总是使用foo()。这种行为类似于“私有抽象”方法,但这在Java中是不可能的。
还有其他选择吗?谢谢!
答案 0 :(得分:4)
如果您不希望子类能够调用此方法,则可以使用策略:将方法的行为提取到接口中,并将此接口的实现传递给对象。 E.g。
IStrategy {
public void fooToImplement();
}
AClass {
public AClass(IStrategy impl) {...}
public void foo() {
...
strategy.fooToImplement();
...
}
}
代表团而不是继承。在java 8中,这会更容易一些。
如果您的IStrategy
实现需要访问对象AClass的数据,您可以尝试将其实现为内部类。
答案 1 :(得分:2)
如果希望覆盖该方法,则子类必须可以看到该方法。
你必须使用一个不扩展AClass
作为调用者的类。
public class BClass extends ACLass {
@Override
protected void fooToImplement() {
System.out.println("override me im famous");
}
}
public class CClass {
private BCLass bInstance;
public void doSomething(){
bInstance.foo();
// !!! NO ACCESS TO fooImplement()
}
}
答案 2 :(得分:1)
由于要在那里实现的子类需要fooToImplement()
,因此无法区分"实现可见性"和"执行权",你不能通过继承来做到这一点。
然而,您可以将您的对象与另一个包含fooToImplement()
的对象组合在一起:
interface FooImplementation {
void fooToImplement(AClass a);
}
public abstract class AClass {
private final FooImplementation fooImpl;
protected AClass(FooImplementation fooImpl) {
this.fooImpl = fooImpl;
}
public void foo() {
...
fooImpl.fooToImplement(this);
...
}
}
但是,这不会阻止课外的任何人使用yourFooImpl.fooToImplement(yourAClass)
。为了防止这种情况,您可以创建一个类,该类提供fooToImplement()
所需的信息,但只能在AClass
内实现:
interface FooImplementation {
void fooToImplement(AClass.AClassFooView a);
}
public abstract class AClass {
private final FooImplementation fooImpl;
protected AClass(FooImplementation fooImpl) {
this.fooImpl = fooImpl;
}
public class AClassFooView {
...
private AClassFooView() {
}
}
public void foo() {
...
fooImpl.fooToImplement(this.new AClassFooView());
...
}
}
但是fooToImplement
可以将对AClassFooView
的引用传递给其他类......
但是,根据您的类的实现者在文档中绝对确定,没有人应该调用fooToImplement()
也可以作为替代。
最终你必须相信实现者,因为还有可能有人使用反射来访问私有成员,反向改造+更改+重新编译你的类等。
答案 3 :(得分:0)
您可以使用AOP,例如将方面@Before添加到fooToImplement()并检查调用的堆栈跟踪并抛出IllegalArgumentException如果fooToImplement()被调用除foo()之外的任何方法,例如:
if(!Thread.currentThread().getStackTrace()[1].getMethodName().equals("foo")) {
throw new IllegalArgumentException("You musn't call fooToImplement() directly"+
", using foo() instead");
}
然而这种方式有两个问题: