1

给定这个类:

abstract class Foo{
    public Foo(){...}

    public abstract void checkable();

    public void calledWhenCheckableIsCalled(){
        System.out.println("checkable was called");
    }
}

是否有任何代码可以放入 Foo 的构造函数中以在calledWhenCheckableIsCalled调用时checkable调用?

注意:这是对我正在从事的实际项目的总体简化。

编辑:我已经实现了模板模式解决方法。我只是想知道是否还有另一种方法可以做到这一点,我错过了。(也许使用反射。)

4

6 回答 6

4

看起来像一个模板方法模式

但是你必须实现Foo.checkable()并引入另一个抽象方法来委托。

abstract class Foo{
    public Foo(){}

    public void checkable(){
        calledWhenCheckableIsCalled();            
        doCheckable();
    } 

    protected abstract void doCheckable();

    public void calledWhenCheckableIsCalled(){
        System.out.println("checkable was called");
    }
}

我还建议checkable()在这种情况下进行最终处理,以便您可以确定checkable()不能以您期望的其他方式实现。

除了布赖恩·罗奇的评论

缺点是受保护的可以在子类中扩展为公共,因此您不能显式强制执行它。

没错,但是Foo如果子类增加了doCheckable. 因此,每当实例化对象时,您都必须引入验证。我建议使用初始化代码,以便在每个存在的构造函数上执行验证。然后不能忘记调用并因此被绕过。

例如:

abstract class Foo {
    { // instance initializer code ensures that enforceDoCheckableVisibility
      // is invoked for every constructor
        enforceDoCheckableVisibility();
    }
    public Foo() {...}
    public Foo(Object o) {...}

    private void enforceDoCheckableVisibility() {
        Class<?> currentClass = getClass();
        while (currentClass != Foo.class) {
            try {
                Method doCheckableMethod = currentClass.getDeclaredMethod("doCheckable");
                if (Modifier.isPublic(doCheckableMethod.getModifiers())) {
                    throw new RuntimeException("Visibility of "
                                  + currentClass.getSimpleName()
                                  + ".doCheckable() must not be public");
                }
            } catch (SecurityException | NoSuchMethodException e) {}
            currentClass = currentClass.getSuperclass();
        }
    }
}

由于检查是使用反射实现的,缺点是它只在运行时检查。所以你当然不会有编译器支持。但是这种方法可以让你强制 a 的实例Foo只有在它履行你的合同时才能存在。

于 2014-01-08T07:14:50.327 回答
2

不,构造函数将在对象初始化期间被调用一次。但是,您可以获得提供实现以调用超类中的方法的子类:

class Bar extends Foo {

    // implementation of abstract method
    public void checkable(){
        super.calledWhenCheckableIsCalled(); // call to parent's method
        ...
    }
}

编辑

你可以通过方面来实现这一点。使用方面,您可以通过引用抽象父方法来拦截对方法的每次调用。这使您免于干扰子代码。然后,您的calledWhenCheckableIsCalled代码将成为拦截代码的一部分。

abstract class Foo {

    // use pointcut to intercept here
    public void checkable();
}
于 2014-01-08T07:11:34.220 回答
0

没有办法,因为您强制该方法在child.

一个尴尬的建议将从子实现中得知。我的意思是没有干净的方法AFAIK

于 2014-01-08T07:11:02.597 回答
0
abstract class foo {

    public abstract void bar();

    public void moo() {
        System.out.println("some code");

        this.bar();

        System.out.println("more code");
    }
}

现在如果moo被调用,bar将使用的底层实现,这只是你想要的一个小的范式转变。

所以你的最终用户会打电话moo而不是bar,但他仍然需要实施bar

于 2014-01-08T07:13:22.797 回答
0

不,抽象方法没有主体。但是,您可以像这样链接您的方法:

abstract class Foo {

    void callMeInstead() {

        // do common

        callMeImplementation();
    }

    abstract void callMeImplementation();
}
于 2014-01-08T07:14:28.530 回答
0

在我看来,您正在寻找模板模式:

public abstract class Template {
    public final void checkable() {
        calledWhenCheckableIsCalled();
        doCheckable();
    }

    protected abstract void doCheckable();

    private  void calledWhenCheckableIsCalled() {
        System.out.println("checkable was called");
    }
}

现在,每次checkable()被调用,calledWhenCheckableIsCalled()也被调用。并且 suclass 仍然必须checkable()通过实现该doCheckable()方法来提供 的实际实现。

请注意,使checkable()final 可以防止子类覆盖它,从而绕过对calledWhenCheckableIsCalled().

于 2014-01-08T07:18:11.830 回答