2014-01-08 3 views
1

Учитывая этот класс:Могу ли я определить, был ли вызван абстрактный метод?

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

    public abstract void checkable(); 

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

Есть ли код, который я могу поставить в конструктор Foo, чтобы сделать calledWhenCheckableIsCalled дозвонились, когда checkable называется?

Примечание: Это грубое упрощение фактического проекта, над которым я работаю.

Редактировать: Я уже реализовал обход шаблона шаблона. Я просто задавался вопросом, есть ли другой способ сделать это, я пропал без вести. (Возможно, используя отражение.)

+2

Erm, no. <----> –

+0

@BrianRoach Вздох, я был уверен, что это не сработает. Это сделало бы функциональность, которую я хочу намного проще реализовать. – Others

+0

Единственный способ, которым вы знаете, 'checkable()' вызывается, помещая в него некоторый код. Или создайте вокруг него метод обертки. – Santosh

ответ

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 Роуча

Недостатком является то, что защищаемый может быть расширена до общественности в подклассе, так что вы не можете явно выполнять его.

Это правда, но вы можете предотвратить 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 мог существовать только в том случае, если он выполняет ваш контракт.

+0

+1 - вот что я получил в своем комментарии. Недостатком является то, что 'protected' может быть расширен до' public' в подклассе, поэтому вы не можете явно его применять. –

+0

@BrianRoach да, вы правы. Я вижу только один способ предотвратить повышение видимости подклассов с помощью проверки отражения в конструкторе. Я обновил свой ответ. Как вы думаете? –

+0

Хе-хе, это, безусловно, способ обеспечить его соблюдение :) Я бы снова поднял вас, если мог. –

0

Нет никакого способа, как вы заставляете этот метод реализовать в child.

Неудобное предложение будет известно из реализации ребенка. Я имею в виду, что нет чистого пути AFAIK

2

Нет, конструктор будет вызван один раз во время инициализации объекта. Однако вы можете получить свой подкласс, который обеспечивает реализацию для вызова метода в родительском классе:

class Bar extends Foo { 

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

EDIT

Вы могли бы добиться этого с аспектами. Используя аспект, вы можете перехватить каждый вызов метода, обратившись к абстрактному родительскому методу. Это позволяет вам не вмешиваться в дочерний код. Тогда ваш код calledWhenCheckableIsCalled станет частью кода перехвата.

abstract class Foo { 

    // use pointcut to intercept here 
    public void checkable(); 
} 
+0

Я вижу, как это сработает, но я действительно не хочу переключиться на использование AspectJ. – Others

+0

+1 Для точки «Аспект». – NINCOMPOOP

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

0

Неа, абстрактный метод не имеет тела. Можно, однако, цепь вашего метода, как это:

abstract class Foo { 

    void callMeInstead() { 

     // do common 

     callMeImplementation(); 
    } 

    abstract void callMeImplementation(); 
} 
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() предотвращает переопределение подкласса и, таким образом, обходя вызов calledWhenCheckableIsCalled().

Смежные вопросы