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

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

public class myMotherClass { 

   myMethod {

      ...some code ..

   }

}

public class myClass extends myMotherClass {

   myMethod {

      ... other code ...
   }

}

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

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

4 ответов


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

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

public abstract class EnforceImplementation extends myMotherClass {

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

        public abstract void implementMyMethod();
}

редактировать

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

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's 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 абстрактный класс и используйте метод шаблона.

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


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

вместо

myClass extends myMotherClass

считают

myClass extends myMotherAbstractClass
myMotherClass extends myMotherAbstractClass 

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


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

public class MyMotherClass { 

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

}

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


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

public interface MyInterface{

   void myMethod();
}

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

public MyClass implements MyInterface{

  public void myMethod{
     // do something
   }

}