web-dev-qa-db-ja.com

「メソッドが多すぎる」ことは、「継承よりも構成」のルールを破る正当な理由ですか?

私は通常、Java GUIの世界に足を踏み入れるまで、「継承よりも構成」のルールに従うことを好みます。

私の経験では、GUIコンポーネントにカスタム要件を追加するために、たとえば、JButtonにカスタム関数を追加するには、通常、次のようにJButtonから拡張するクラスを作成します。

public class CustomButton extends JButton{
    public void customMethod(){
    }
}

私は明らかに「継承よりも構成」ルールに違反していると思うので、継承ではなく構成によってこれを達成しようとしますが、問題が発生します。 :

public class CustomButton{
    protected JButton button;
    public void customMethod(){
    }

    public void add(PopupMenu popup){
        button.add(popup);
    }

    public void addActionListener(ActionListener l){
        button.addActionListener(l);
    }

    .
    .
    .
}

jButtonにマップするには、メソッドの恐ろしいリストが必要になる場合があります。

また、もう1つの問題があります。CustomButtonがJButtonのサブクラスではない場合、パラメーターとしてJButtonを必要とする組み込みメソッドを処理する方法がわかりません。

だから私の質問は、元のクラスにあまりにも多くのメソッドがある場合、構成の代わりに継承を使用するのが合理的ですか?

6
ggrr

継承の合成 がここで実際に言わなければならないことは、JButtonが合成多型で設計されていて、CutomButtonメソッドがそれ。そうではなかった。

クライアントがJButtonが提供するすべてにアクセスする必要がある場合(疑わしい)、逆に構成を行う場合は、一連のボイラープレート委譲メソッドを作成する必要があります。このようなばかげた作業を自動リファクタリングで行うことができますが、それでもメンテナンスは面倒です。誰がそれを見たいのですか?ブレー。

つまり、継承を行います。それは何を傷つけますか?まあ ヨーヨー問題 は面白くない。複数のレベルの継承を作成しないことでそれを回避できます。それに関する問題は、あなたが「大丈夫だ」と思ったということです。そして次の男もそうです。そして次。

クラスでfinalを使用してこれを停止できますが、次の人には F.U。 です。次の人のために、JButtonの人があなたのためにしたいことをすることができます。呼び出すcustomMethod()CustomInterfaceを実装するものを渡してもらいます。これのファンシーな名前は object adapter pattern です。

enter image description here

これで、継承と構成の両方を実行しましたが、少なくとも狂気は終わらせることができます。

6
candied_orange

正直なところ、JButtonと同じくらい一般的なコンポーネントが本当に必要な場合は、継承を使用する必要があります。 「継承より優先する構成」は、「継承を使用しない」という意味ではありません。ただし、初心者が継承が必要であると考える時間の95%は継承を必要としないため、人々はその流行語句を作成しました。

95%の確率で、実際にはJButtonほど一般的なコンポーネントは必要ありません。より具体的なものが必要です。たとえば、これは私がJava少し前に書いたものですが、電卓アプリのカスタムボタンのパブリックインターフェイス全体です。

public interface Button
{
    public void setOperation(Operation operation);
    public Operation getOperation();
    public void setEnabled(boolean enabled);
}

構成されたオブジェクトのすべてのセットアップは、コンストラクターで行われました。これには、クリックされたときに現在設定されている操作の主要機能を呼び出すイベントハンドラーが含まれます。このインターフェースを見ると、Swing GUIによって実装されたとは思わないでしょう。これは、コアコードのほとんどを再利用してAndroid。私のインターフェースはセマンティックであり、ランダムなGUIライブラリのニーズではなく、アプリケーションのニーズに結びついています。

ほぼ正確なコピーバージョンではなく、自分のものに似たインターフェイスを持つカスタムGUIコンポーネントの記述方法を学ぶと、継承よりも構成の利点がわかりやすくなります。

16
Karl Bielefeldt

質問の前提は間違っているようです。コンポジションを使用すると、ボタンhasであるものを作成しますが、ボタン自体ではありません。構成は、継承を直接置き換えるものではありません。

JButtonはビューです。クラスは、ボタンをその一部として持つ別のビューか、ボタンを監視するコントローラーです。どちらにしても、ボタンではありません。そして、だれもその上でボタンメソッドを呼び出すことができるとは期待していません。

プロパティにメソッドを委任する必要があるのは、たとえばデコレータパターンのように、契約を履行する必要がある場合のみです。ボタンにアクセスする必要がある場合は、メソッドの部分的な委譲ではなく、getterメソッドを介してボタンを公開します。

2
null

あなたが最も頻繁に使用するデリゲートメソッドを実装することができます。他のすべてのものは、クライアントがJButtonを取得する方法があることを確認してください:

public class CustomButton {
    protected JButton button;

    public void customMethod() {
    }

    public void add(PopupMenu popup) {
        button.add(popup);
    }

    public void addActionListener(ActionListener l) {
        button.addActionListener(l);
    }

    public JButton getButton() {
        return button;
    }
}

次に、たとえばボタンを無効にします。

customButton.getButton().setEnabled(false);
0

あなたのケースでは、カスタムメソッドを使用していくつかのプロパティをJButtonに設定しようとしているJButtonメソッドをオーバーライドしていないため、継承を使用する必要はありません。 Builder Design Patterを使用できます。
例えば

public class CustomButtonBuilder {

      private JButton button;

      public CustomButtonBuilder(JButton button) {
             this.button = button;
      }

      // the build method is your same customMethod()
      public void build() {
      // here goes the custom setting for your button.
      }
}

上記の例では、JButtonが作成され、必要なリスナーなどがセッターメソッドを使用して設定されます。次に、CustomButtonBuilderに渡され、カスタム機能がJButtonオブジェクトに追加されます。

このようにして、それほど多くのメソッドを記述することなく、継承より構成を選択できます。

0
Sudheer