Как принудительно реализовать метод в подклассе без использования абстрактных?

Я хочу заставить подкласс реализовать реализованный метод моего материнского класса. Я смотрю это Java - принудительная реализация реализованного метода, но я не могу преобразовать свой класс мамы в абстрактный класс.

public class myMotherClass { 

   myMethod {

      ...some code ..

   }

}

public class myClass extends myMotherClass {

   myMethod {

      ... other code ...
   }

}

Итак, в этом примере я хочу заставить myClass реализовать myMethod.

Извините за мой английский...

Ответ 1

Вы не можете заставить подкласс переопределить метод. Вы можете только заставить его реализовать метод, сделав его абстрактным.

Итак, если вы не можете сделать myMotherClass abstract, вы можете ввести еще один суперкласс, который расширяет myMotherClass и делегирует метод, который должен быть реализован:

public abstract class EnforceImplementation extends myMotherClass {

        public final void myMethod(){
             implementMyMethod();
        }

        public abstract void implementMyMethod();
}

ИЗМЕНИТЬ

Я нашел еще один интересный способ решения проблемы в hemcrest api, т.е. используемый mockito.

public interface Matcher<T> extends SelfDescribing {

    /**
     * Evaluates the matcher for argument <var>item</var>.
     * <p/>
     * This method matches against Object, instead of the generic type T. This is
     * because the caller of the Matcher does not know at runtime what the type is
     * (because of type erasure with Java generics). It is down to the implementations
     * to check the correct type. 
     *
     * @param item the object against which the matcher is evaluated.
     * @return <code>true</code> if <var>item</var> matches, otherwise <code>false</code>.
     *
     * @see BaseMatcher
     */
    boolean matches(Object item);

    /**
     * This method simply acts a friendly reminder not to implement Matcher directly and
     * instead extend BaseMatcher. It easy to ignore JavaDoc, but a bit harder to ignore
     * compile errors .
     *
     * @see Matcher for reasons why.
     * @see BaseMatcher
     */
    void _dont_implement_Matcher___instead_extend_BaseMatcher_();
}

В интерфейсе указан метод _dont_implement_Matcher___instead_extend_BaseMatcher_. Конечно, это не мешает другим реализовать интерфейс Matcher, но он направляет разработчика в правильном направлении.

И класс BaseMatcher реализует метод _dont_implement_Matcher___instead_extend_BaseMatcher_ как окончательный

public final void _dont_implement_Matcher___instead_extend_BaseMatcher_() {
    // See Matcher interface for an explanation of this method.
}

Наконец, я думаю, что это проблема дизайна, потому что BaseMatcher obviouosly реализует логику, которую должен реализовать каждый Matcher. Таким образом, было бы лучше сделать Matcher абстрактным классом и использовать шаблонный метод.

Но я думаю, что они сделали это, потому что это был лучший компромисс между совместимостью байт-кода и новыми функциями.

Ответ 2

Вы можете переделать свою иерархию, чтобы ваши конкретные классы были только листьями дерева.

Вместо

myClass extends myMotherClass

Рассмотрим

myClass extends myMotherAbstractClass
myMotherClass extends myMotherAbstractClass 

Таким образом, класс Abstract наследуется обоими экземплярами. Вероятно, в этом случае myMotherClass будет чрезвычайно тонким, просто реализация myMethod.

Ответ 3

Одна вещь, которую большинство людей игнорирует, - это следующая реализация (хотя я заметил упоминание об этом в комментарии):

public class MyMotherClass { 

    public void myMethod() {
      throw new RuntimeException("Method not overwritten");
    }    

}

В большинстве случаев этого должно быть достаточно, так как вы должны иметь некоторую форму приемочного тестирования (даже если это только проверка класса наследования вручную). Теоретически вы все еще представляете, что никто не поймет, что метод не был перезаписан до производства.

Ответ 4

Если вы действительно хотите заставить использовать метод, используйте interface.

public interface MyInterface{

   void myMethod();
}

Теперь, если кто-то хочет реализовать из этого интерфейса как MyClass implements MyInterface, вам нужно реализовать myMethod();

public MyClass implements MyInterface{

  public void myMethod{
     // do something
   }

}