2017-06-16 14 views
1

私は現在、Bで使用したいいくつかの機能を持つクラスAを持っています.AにはButton型のメンバ変数があり、BIでは型を使用したいIconButton(Buttonから派生したもの)。派生クラスのメンバ変数に派生型を使用

クラスは、このようなものです:あなたが見ることができるように

public class A { 

    protected Button x = new Button(); 

    A() { 
     x.xx(); 
    } 

    public void doFirstThing() { 
     x.xx(); 
    } 

    Button getButton() { 
     return x; 
    } 
} 

public class B extends A { 

    B() { 
     x = new IconButton(); 

     getButton().yy(); 
    } 

    public void doSecondThing() { 
     getButton().zz(); 
    } 

    IconButton getButton() { 
     return (IconButton) x; 
    } 
} 

public class Button { 

    public void xx() { 

    } 
} 

public class IconButton extends Button { 

    public void yy() { 

    } 

    public void zz() { 

    } 
} 

、方法yy()zz()は、このように私は方法getButtonを提供することにより、Bの「回避策」を実行する必要があり、IconButtonでのみ使用可能です。

そして、我々はあまりにもでgetButton()方法を持っていると思いますので、これはB.

にこじつけ加えていない。しかし、私は思ったんだけど、はい、通常、これは本当に正しい方法ですか、私はそれを間違っている?

私は抽象クラスを作成することも考えました。 A.から現在のコードを含んでいるでしょうA0は、その後、私はちょうど作りたい:

class A extends A0<Button> { 
// mostly empty, code taken from A0 
} 

class B extends A0<IconButton> { 
// custom things here 
} 

またはこの問題のために、本当に優れている他の方法があるの?

これはGWTアプリケーションのコンポーネントです。ですから、@king_nakのように宣言すれば、コンポーネントに2つのボタンがあります。また、別の回避策を講じても問題が解決しない場合は、Bの元のボタンを削除することができます。 x.removeFromParent()かそのようなものですが、それはまったく新しいレベルの悪い習慣になってしまいます。

+0

抽象クラス 'についてのAフィールド' T X 'と '何'クラスBはA 'を拡張しますか? –

+0

ある時点でクラスAのインスタンスを構築するつもりかどうかはわかりません。もしそうなら、 'IconButton getButton()'が必須ではないことを除いて、それは大丈夫です。 'A'のインスタンスを作成しない場合は、それを抽象化します。 – KarelG

+0

IconButtonはB.の実装の詳細です.IconeButtonとButtonをこれらのクラスのクライアントに公開する理由は? – davidxxx

答えて

1

あなたの回避策が悪いですアイディア。あなたはタイプセーフティーの多くを失う。たとえば、コンストラクタをBに変更してx = new Button();に変更し、キャストを忘れてしまいます。あなたのプログラムはまだコンパイルされますが、実行時には失敗します。

私はあなたが共通の一般的なスーパークラスで適切な道にいると思います。 A0A0<T extends Button>、メンバーをT xと定義することができます。より良い解決策があるかもしれませんが、大きな画像なしでは伝えるのは難しいです。

 
public class PlainButton implements Button { 
    public void init() { 
     xx(); 
    } 
    private void xx() { 
    } 
} 
  • IconButtonクラスを作成します:あなたの元A(ButtonWrapperクラスを作成します
  •  
    public class IconButton implements Button { 
        public void init() { 
         yy(); 
         zz(); 
        } 
        private void yy() { 
        } 
        private void zz() { 
        }   
    } 
    
    および/または

  • +0

    私は私のusecaseについての詳細を私の質問を更新しました。それはGWTアプリです(AとBは本当にコンポーネントです)、yy()とzz()はAとBの多くの場所で使用する必要があります – ramcrys

    +0

    @ramcrysいいえ、私はGWTの専門家ではありません。この問題を徹底的に解答するには、これは広範なstackoverflowになります。 –

    +0

    答えを受け入れました:)私はすでに行っています私のコードでジェネリックのアプローチを使っています。将来の運賃を守る必要があります。 – ramcrys

    0

    簡単(および多型)の方法は、例えば、代わりにすべてのクラスの参照を持つのクラスBにgetButtonをオーバーライドしてIconButtonのインスタンスを返すために、次のようになります。

    public class A { 
        public Button getButton(){ 
         Button b = new Button(); 
         b.xx(); 
         return b; 
        } 
    } 
    
    public class B extends A { 
    
        @Override 
        public Button getButton(){ 
         IconButton b = new IconButton(); 
         b.yy(); 
         b.zz(); 
         return b; 
        } 
    } 
    
    +0

    この状況では、私に尋ねると、よりクリーンなコードにつながる工場のデザインパターンがあります。 – KarelG

    +0

    'getButton'メソッドによって返されるインスタンスの型が、それをオーバーライドするクラスに依存する場合、私はむしろファクトリメソッドを実装するよりもこの方法で行きます。 –

    +0

    型(クラスに依存する)が 'Button'から継承されているのであれば、なぜそうしますか?クリーンなアプローチはインターフェイスですが、私はOPのインデントがきれいではないので、このような状況ではわかりません。ソフトウェアソリューションを設計するとき、この種の議論はかなり普通です。 – KarelG

    0
    1. 抽出ボタンインターフェース
       
      public interface Button { 
          void init(); 
      } 
      
    2. はPlainButton(あなたの元ボタン)クラスを作成します。 Bクラス):
       
      public class ButtonWrapper { 
          private final T button; 
          public ButtonWrapper(T button) { 
           this.button = button; 
           this.button.init(); 
          } 
          public T getButton() { 
           return button; 
          } 
      } 
      
    3. 用途:

       
      ButtonWrapper A = new ButtonWrapper(new PlainButton()); 
      ButtonWrapper B = new ButtonWrapper(new IconButton()); 
      
    0

    あなたの唯一の懸念はBIconButtonそれは拠点Buttonだているはずの代わりにすることを、なぜBにそれのための別部材を作成し、その使用をさせていない場合は?

    class A { 
        protected Button b; 
        public A() { 
         // By default, I use a Button 
         b = new Button(); 
        } 
    
        // Subclasses can override which button I use 
        protected A(Button b) { 
         this.b = b; 
        } 
    
    } 
    
    class B extends A { 
        private IconButton ib; 
        public B() { 
         super(new IconButton()); 
         ib = (IconButton) super.b; 
        } 
    
        // B can access it's IconButton through ib 
        // Users of A will see a Button 
    } 
    

    抽象基本クラス、Generics、Wrappersは必要ありません。あなたがジェネリックを使用したくない場合は、単に

    +0

    Ahhhhh ...これは私のGWTアプリではコンポーネントの一種だと言いました。だから、あなたが言ったように宣言すれば、コンポーネントに2つのボタンがあります(あるいは、もう1つの回避策で暮らしていれば、Bの元のボタンを削除できます) – ramcrys

    +0

    B.インスタンス化するときに1つのボタンしかありません。サブクラスがボタンを提供するとき、ボタンは決してボタンを作成しません。または、生成されたコードを扱っていますが、このアプローチを使用できませんか? –

    +0

    うわー..これが私の必要としているようです。しかし、それは概念的にちょうど1つでなければならない2つのもの(bとib)があるとき、それは奇妙に見えるか、ここで悪い練習を導入するのだろうか? あなたのアプローチは実際には最高のものかもしれませんが、本当にクリーンなデザインですか? – ramcrys

    0

    BはそれがIconButtonだ持っており、それに2つの参照持ってみましょう(B.ibをしてA.bを継承): このアプローチはbest practicesに反するが、私は限り、あなたはいけないとして、それは完全に罰金見つけますボタンでBのコンストラクタで何か:今、あなたは、私が最も可能性の高い自分自身を使用していないだろうこのクレイジーなアプローチを使用することができますキャストを避けたい場合は

    public static class A { 
    
        protected Button x = null; 
    
        public A() { 
         x = createButton(); 
        } 
    
        public Button getButton() { 
         return x; 
        } 
    
        protected Button createButton(){ 
         Button result = new Button(); 
         result.xx(); 
         return result; 
        } 
    } 
    
    public static class B extends A{ 
    
        public IconButton getButton() { 
         return (IconButton)x; 
        } 
    
        protected Button createButton(){ 
         IconButton iconButton = new IconButton(); 
         iconButton.yy(); 
         iconButton.zz(); 
         return iconButton; 
        } 
    } 
    

    。ご自身の責任で警告使用:

    public static class A { 
    
         protected Button x = null; 
    
         public A() { 
          x = createButton(); 
         } 
    
         public Button getButton() { 
          return x; 
         } 
    
         protected Button createButton(){ 
          Button result = new Button(); 
          result.xx(); 
          return result; 
         } 
        } 
    
        public static class B extends A{ 
    
         //leave uninitialized so that when B gets constructed iconButton wont be reinitialized because it has been initialized by A's constructor call 
         private IconButton iconButton; 
    
         public IconButton getButton() { 
          return iconButton; 
         } 
    
         protected Button createButton(){ 
          iconButton = new IconButton(); 
          iconButton.yy(); 
          iconButton.zz(); 
          return iconButton; 
         } 
        } 
    

    更新:

    としては好ましい方法は、ここで継承を回避し、必要に応じて組成物を使用することである議論。しかし、サンプルコードではコンポジションアプローチを表示できるように詳細があまりないので、継承を使用する別のアプローチを追加しています。キャストおよび構築の初期化を回避します。 私はそれが代わりに建設初期のスイングやGWTなどの非同時フレームワークで作業するとき遅延初期化を使用するのが最善だと思う:

    ​​
    +0

    実際には、私はBのコンストラクタでxを使用するだけではありません。つまり、Bに何かを呼び出す方法がたくさんあるかもしれません特別(IconButtonからのみ)。そして、私たちは元の回避策に頼らざるを得ません。すべての場所でgetButton()を呼び出す必要があります:( – ramcrys

    +0

    'iconButton'の初期化コードを' createButton() 'の中に入れておく必要があります。 – tsolakp

    +0

    はい初期化しかし、createButton()でコードを作成することはできません。しかし、たとえばB.handlerForEventXXX()メソッドをx.yy()を呼び出す必要があるとすれば、これは不可能です。> getButton()。yy()を呼び出す必要があります。 – ramcrys