0

私は巨大なプロジェクトに2つの親クラスを持っていClassAますClassB。各クラスには多くのサブクラスがあり、サブクラスには多くのサブクラスがあり、サブクラスにも多くのサブクラスがあります。

私の仕事は、これらの 2 つの「家族」を「結婚」させて、両方とも単一の親から継承することです。私は基本的ClassAClassB、結合されたサブクラス (子) の両方に対して 1 つのクラス (親) を作成する必要があります。

ClassAClassB両方が現在実装されていSerializableます。

現在、両方の継承チェーンを から継承さClassAせ、すべての関数とデータ メンバーを からClassBにコピーしようとしていClassAます。これは退屈で、ひどい解決策だと思います。

この問題を解決する正しい方法は何ですか?

編集 - いくつかの説明

ClassAそしてClassB本質的に同じことを行います(もちろん、一連の多くのクラスとメソッド呼び出しを介して、多くのストアドプロシージャへの多くの呼び出し)。

ClassAただし、実装した新しいサービス ベース (Jersey) アーキテクチャを介してストアド プロシージャの半分を呼び出します。基本的に、「FamilyA」ですでに行われているのと同じ方法で、新しいサービス指向機能を「FamilyB」に実装しています。問題は、これらのファミリのそれぞれが巨大であることです。多くのクラスと長い継承チェーンがあり、小さな変更を加えると継承チェーンにバタフライ効果が生じます。

明確化が必要な場合は、お知らせください。

4

3 に答える 3

3

頭に浮かぶ最初の答えは、「一般的にはノー」です。

これが合理的であるためには、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 つの継承ツリーのメソッドの呼び出し元を変更したい場合ですが、それが必要であると考える理由は (まだ) ありません。うまくいけば、すべてのメソッドには、少なくともその機能を説明し、渡す必要のあるパラメーターを渡す適切な名前が付けられ、上部のリファクタリングは呼び出しではなく実装にのみ影響します。とにかく、それは十分に大きな仕事のように見えます。関数だけでなく呼び出しも変更する必要がないことを願っています。

于 2013-11-08T21:45:49.547 に答える
1

ClassA私の本能は、メンバーとしてとのオブジェクトを持つ新しいクラスを作成し、それをとClassBの両方から本質的に派生させたいものの基本クラスとして使用することです。例えば:ClassAClassB

class ClassAB
{
    private ClassA a;
    private ClassB b;

    public void doSomething()
    {
         a.doSomething();
    }

    public void doSomethingElse()
    {
         b.doSomethingElse();
    }

    ...
}

確かに面倒ですが、やり直してこれを可能にするよりもはるかに簡単で、バグにつながる可能性がはるかに低いClassAようClassBです。この場合、それは機能しますか?

于 2013-11-08T21:45:49.197 に答える