提供抽象方法的实现但限制可见性
Provide implementation for abstract method but restrict visibility
我在抽象 class 中有一个调用抽象方法的方法,subclasses 必须为其提供实现。
public abstract class AClass {
public void foo() {
...
fooToImplement();
...
}
// DON'T CALL THIS METHOD, ONLY PROVIDE IMPLEMENTATION!
protected abstract void fooToImplement();
}
我想确保子classes 不调用 fooToImplement(),它们应该始终使用 foo()。该行为类似于 "private abstract" 方法,但在 Java.
中是不可能的
有其他选择吗?谢谢!
您可以对此使用 AOP,例如将方面 @Before 添加到 fooToImplement() 并检查调用的堆栈跟踪,如果 fooToImplement() 被调用除 foo() 之外的任何方法,则抛出 IllegalArgumentException,例如:
if(!Thread.currentThread().getStackTrace()[1].getMethodName().equals("foo")) {
throw new IllegalArgumentException("You musn't call fooToImplement() directly"+
", using foo() instead");
}
但是这种方式有两个问题:
- 性能
- 运行时异常
如果您不希望您的子classes 能够调用此方法,您可以使用策略:将方法的行为提取到接口中并将此接口的实现传递给对象.例如
IStrategy {
public void fooToImplement();
}
AClass {
public AClass(IStrategy impl) {...}
public void foo() {
...
strategy.fooToImplement();
...
}
}
委托而不是继承。在 java 8 中,这会更容易一些。
如果您的 IStrategy
实现需要访问对象 AClass 的数据,您可以尝试将其实现为内部 class.
如果您希望覆盖该方法,则您的子class 必须可以看到该方法。
您必须使用 class 不扩展 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()
}
}
由于 fooToImplement()
需要对 subclasses 可见才能在那里实现,并且无法区分 "implement visibility" 和 "execution rights",你不能通过继承来做到这一点。
但是,您可以将您的对象与另一个包含 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);
...
}
}
但是,这不会阻止 class 以外的任何人使用 yourFooImpl.fooToImplement(yourAClass)
。为防止这种情况,您可以创建一个 class 来提供 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
的引用传递给其他 classes...
然而,根据您的 class 的实现者,在文档中绝对确定,没有人应该调用 fooToImplement()
也可能是一个替代方案。
最终你必须相信实现者,因为也有可能有人使用反射来访问私有成员,逆向工程+更改+重新编译你的 class 等..
我在抽象 class 中有一个调用抽象方法的方法,subclasses 必须为其提供实现。
public abstract class AClass {
public void foo() {
...
fooToImplement();
...
}
// DON'T CALL THIS METHOD, ONLY PROVIDE IMPLEMENTATION!
protected abstract void fooToImplement();
}
我想确保子classes 不调用 fooToImplement(),它们应该始终使用 foo()。该行为类似于 "private abstract" 方法,但在 Java.
中是不可能的有其他选择吗?谢谢!
您可以对此使用 AOP,例如将方面 @Before 添加到 fooToImplement() 并检查调用的堆栈跟踪,如果 fooToImplement() 被调用除 foo() 之外的任何方法,则抛出 IllegalArgumentException,例如:
if(!Thread.currentThread().getStackTrace()[1].getMethodName().equals("foo")) {
throw new IllegalArgumentException("You musn't call fooToImplement() directly"+
", using foo() instead");
}
但是这种方式有两个问题:
- 性能
- 运行时异常
如果您不希望您的子classes 能够调用此方法,您可以使用策略:将方法的行为提取到接口中并将此接口的实现传递给对象.例如
IStrategy {
public void fooToImplement();
}
AClass {
public AClass(IStrategy impl) {...}
public void foo() {
...
strategy.fooToImplement();
...
}
}
委托而不是继承。在 java 8 中,这会更容易一些。
如果您的 IStrategy
实现需要访问对象 AClass 的数据,您可以尝试将其实现为内部 class.
如果您希望覆盖该方法,则您的子class 必须可以看到该方法。
您必须使用 class 不扩展 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()
}
}
由于 fooToImplement()
需要对 subclasses 可见才能在那里实现,并且无法区分 "implement visibility" 和 "execution rights",你不能通过继承来做到这一点。
但是,您可以将您的对象与另一个包含 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);
...
}
}
但是,这不会阻止 class 以外的任何人使用 yourFooImpl.fooToImplement(yourAClass)
。为防止这种情况,您可以创建一个 class 来提供 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
的引用传递给其他 classes...
然而,根据您的 class 的实现者,在文档中绝对确定,没有人应该调用 fooToImplement()
也可能是一个替代方案。
最终你必须相信实现者,因为也有可能有人使用反射来访问私有成员,逆向工程+更改+重新编译你的 class 等..