頭に浮かぶ最初の答えは、「一般的にはノー」です。
これが合理的であるためには、A と B は他の何かの特殊なケースでなければなりません。
それ以外に、コードを結合する理由は見当たりません (そして、結合しない理由はたくさんあります)。単純に両方に X を拡張させて、すべてのコードをそのままにしておくことができない理由はありますか?
明確な全体像を把握するのに十分な情報はまだないと思いますが、これまでに得た情報を使用します。
クラス A とクラス B の両方が拡張するクラス X を実装しても、サブクラス、またはいずれかのクラスまたはサブクラスの使用については何も変わりません。それは確かに私が始めるところです。
public Class X implements Serializable {}
public Class A extends X implements Serializable
{
// retain all current code to start
}
public Class B extends X implements Serializable
{
// and here be all current code also
}
あなたは現在、クラス B をクラス A にマージすることを考えていると言います。これには問題がありそうです。A と B はコードの「約半分」を共有し、その下に大きな継承ツリーがあります。クラス A のサブクラスをインスタンス化するものは、A に新しい機能を持たせることで動作を変更できます。
代わりに、A から X へ、B から X へゆっくりと移動します。A ツリーと B ツリーの間に共通性がある場合にのみ、移動しようとします。
たとえば、同じ機能を持つメソッド abc() が A にあり、def() が B にあるとします。この機能を X に移動して、好きな名前を付けることができます。おそらく、その機能を最もよく表していると思われる名前を付けようとするでしょう。次に、abc() と def() がこの新しい関数を呼び出し、これらのメソッドのコードを両方から削除できます。
public class X implements Serializable
{
public void abcdef()
{
// common functionality, merged from A and B
}
}
public class A extends X implements Serializable
{
public function abc() { abcdef(); }
}
public class B extends X implements Serializable
{
public function edf() { abcdef(); }
}
このように進める利点の 1 つは、各ステップで何が行われたかが明確になることです。リファクタリングされた両方のメソッドの機能が完全で正しいことを保証するために、コメントでマークを付けてレビューしたり、テストを行ったりすることができます。これは、レビューやテスト用の適切な設定があるかどうかに応じて、1 つ、2 つ、またはそれ以上のメソッドがリファクタリングされた後に実行できます。
これが壊れる唯一のケースは、何らかの理由で 2 つの継承ツリーのメソッドの呼び出し元を変更したい場合ですが、それが必要であると考える理由は (まだ) ありません。うまくいけば、すべてのメソッドには、少なくともその機能を説明し、渡す必要のあるパラメーターを渡す適切な名前が付けられ、上部のリファクタリングは呼び出しではなく実装にのみ影響します。とにかく、それは十分に大きな仕事のように見えます。関数だけでなく呼び出しも変更する必要がないことを願っています。