我可以判断一个抽象方法是否已被调用?

时间:2014-01-08 07:06:40

标签: java design-patterns reflection abstract-methods

鉴于此课程:

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

    public abstract void checkable();

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

我可以在Foo的构造函数中添加任何代码,以便在调用calledWhenCheckableIsCalled时调用checkable吗?

注意:这是我正在进行的实际项目的大致简化。

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

6 个答案:

答案 0 :(得分:4)

看起来像template method pattern

但是你必须实现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()无法以您预期的其他方式实现。

除了Brian Roach的评论

  

缺点是受保护的内容可以在子类中扩展为public,因此您无法明确强制执行。

这是事实,但是如果子类增加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();
        }
    }
}

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

答案 1 :(得分: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();
}

答案 2 :(得分:0)

您无法在child中强制实施该方法。

从儿童实施中可以了解到一个尴尬的建议。我的意思是没有干净的方式 AFAIK

答案 3 :(得分: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

答案 4 :(得分:0)

不,抽象方法没有正文。但是,你可以像这样链接你的方法:

abstract class Foo {

    void callMeInstead() {

        // do common

        callMeImplementation();
    }

    abstract void callMeImplementation();
}

答案 5 :(得分: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()。而且,通过实施checkable()方法,蔗糖仍然必须提供doCheckable()的实际实施。

请注意,使checkable()为final会阻止子类覆盖它,从而绕过对calledWhenCheckableIsCalled()的调用。