web-dev-qa-db-ja.com

抽象を使用せずにサブクラスでメソッドの実装を強制する方法は?

サブクラスに母クラスの実装済みメソッドを実装するように強制したい。私はこれを見る Java-実装されたメソッドの実装を強制する が、母クラスを抽象クラスに変換できない。

public class myMotherClass { 

   myMethod {

      ...some code ..

   }

}

public class myClass extends myMotherClass {

   myMethod {

      ... other code ...
   }

}

したがって、この例では、myClassにmyMethodを実装させる必要があります。

私の英語でごめんなさい...

16
Maniz

サブクラスにメソッドをオーバーライドさせることはできません。メソッドを抽象化することによってのみ、メソッドの実装を強制できます。

したがって、myMotherClassを抽象化できない場合は、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'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_メソッドをfinalとして実装します

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

最後に、BaseMatcherはすべての Matcher が実装する必要のあるロジックを明白に実装しているため、これは設計上の問題だと思います。したがって、 Matcher を抽象クラスにして、テンプレートメソッドを使用する方がよいでしょう。

しかし、バイトコードの互換性と新機能との間の最良の妥協であったため、彼らはそれをしたと思います。

18
René Link

具象クラスがツリーのリーフのみになるように、階層を作り直すことができます。

の代わりに

myClass extends myMotherClass

検討する

myClass extends myMotherAbstractClass
myMotherClass extends myMotherAbstractClass 

このように、Abstractクラスはインスタンス化された両方のクラスによって継承されます。この場合、myMotherClassmyMethodの実装だけで非常に薄くなる可能性があります。

6
Karthik T

ほとんどの人が見落としていることの1つは、次の実装です(ただし、コメントでそれについて言及しました)。

public class MyMotherClass { 

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

}

何らかの形で受け入れテストが必要なので、ほとんどの場合これで十分です(継承クラスを手動でテストするだけの場合でも)。理論的には、この方法が生産されるまで見過ごされなかったことに誰も気づかない可能性をまだ導入しています。

2
bnunamak