2017-01-30 12 views
1

私は、サブクラスの様々なサブクラス(X、Y、Zと呼ぶことができます) (A、B、Cと呼ぶ)を抽象クラス(それをBarと呼ぶ)のクラスと呼ぶ。しかし、それらのすべてに同じメソッドを書く(コピーする)ことは無駄だと感じています。Java:ラップされたクラスをインスタンス化する抽象クラスのサブクラスのラッパークラスを作成する方法

このように、私はX、Y、Zレイヤーを削除し、FooInterfaceにBar-instancesをラップする実際のクラスFooを作ることにしました。 Tのインスタンスを取得することは非常に困難であると考えられるよう

public abstract class Bar {/*code*/} 

public class A extends Bar {/*code*/} 
public class B extends Bar {/*code*/} 
public class C extends Bar {/*code*/} 

/* 
* Removed thanks to using the nifty wrapper Foo now! 
* I am so happy I decided to do this, 
* can't imagine the horrors I would dream of at night if I had 
* an extra redundant class for each subclass of Bar like this! 
* public class X extends A implements FooInterface {/*implementing FooInterface*/} 
* public class Y extends B implements FooInterface {/*implementing FooInterface*/} 
* public class Z extends C implements FooInterface {/*implementing FooInterface*/} 
*/ 

public class Foo<T extends Bar> { 
    private T t; 
    public Foo() {t = /*code instantiating T*/} 
    //code implementing the methods from FooInterface 
} 

はこのしかし、動作しません。しかし、私はこれを行うための良い方法を見つけ出すように見えることはできません、私の最初に考えたのは、一般的なラッパークラスでしたJavaでジェネリック型を使用する場合

私の代わりに列挙さTを有することに類似した何かやってみなさ:

public class Foo<T extends BarType> { 
    public enum BarType { A, B, C; } 
    private T t; 
    public Foo() { 
     switch(T) { 
      // code instantiating t by using an ugly hard-coded switch-case... 
      // please don't make me! 
     } 

     //code implementing the methods from FooInterface 
    } 
} 

をしかし、私は正直1はこのように列挙型を使用することができるだろうか想像することはできません。したがって、この時点で、私は真剣に、空のコンストラクタをあきらめる考慮し、の線に沿って何かやっている:私は、このバージョンに、より傾斜していますハードコーディングされたスイッチ・ステートメントを行うことを避けるために

// No longer generic and instead pass type to constructor! 
public class Foo { 
    public enum BarType { A, B, C; } 
    private T t; 
    public Foo(Bartype bartype) { 
     switch(T) { 
      // code instantiating t by using an ugly hard-coded switch-case... 
      // please don't make me! 
     } 

     //code implementing the methods from FooInterface 
    } 
} 

けれどもを:

public class Foo<T extends Bar> { 
    private T t; 
    // Foo is used as such: 'Foo<T> foo = new Foo<T>(T.class);' 
    public Foo(Class<T> clazz) throws InstantiationException, 
      IllegalAccessException { 
     // why is it customary to spell this with z? 
     t = clazz.newInstance() 

     //code implementing the methods from FooInterface 
    } 
} 

Javaでこのようなラッパーを正しく作成するにはどうすればよいですか?私は、ジェネリッククラスでコンストラクタにファクトリを渡したり、そのParameterizedTypeを実行したり、コンストラクタに直接正しいクラスのインスタンスを渡したりするなど、他の方法も考慮しました。しかし、それらはすべて、大変面倒で、かなり醜いものだと思います。そのような列挙型のハードコード化されたスイッチケースを好むでしょう...

EDIT: なぜ私はBarはFooInterfaceを実装しています.Barは素敵な純粋なデータ構造であり、FooInterfaceの役割は、より特殊化された実装に役立ついくつかのメソッドを持つことです。たとえば、たとえばバーなど、通常のリスト(そう、その可能性は、私はそれらを実装しても1ではないよ)ですが、その後、私の実装では、どれがクールであるのを追跡するためにあります

public abstract class List; // Bar 
public class LinkedList extends List; // A 
public class ArrayList extends List // B 
public interface CoolLists { // FooInterface 
    boolean isCool(); 
    void setCool(boolean cool); 
} 
public class CoolLinkedList extends LinkedList implements CoolList; // X 
public class CoolArrayList extends ArrayList implements CoolList; // Y 

そして、いや、私は実際にはリストを再実装していません、私は 'クールなリスト'を追跡したい場合は、それらにブール値を格納せず、代わりに 'クール'のものを格納するHashSetのようなものを使用します:P

+1

このような状況になるにはどうすればよいですか?これは読めるほど混乱しています。 – Locke

+0

FooでFooInterfaceを実装したことから、私はすべてのケースでFooInterfaceが実装されているという結論に至りました。それではなぜFooとBarを束縛して継承することを主張しているのですか? FooはBarクラスを含んでいませんか? –

+0

このクラス階層の設計には問題があるようです。 'bar'を' FooInterface'に拡張することはできませんか? – whaleberg

答えて

3

Class<T>を渡す代わりに、Supplier<T>Fooのコンストラクタに渡す必要があります。インスタンスを取得するには、t = supplier.get();を呼び出します。これにより、反射問題に対処する必要がなくなります。サプライヤーを取得するにはA::newB::newまたはC::newのいずれかを使用できます。 Fooのインスタンスを作成するには、呼び出します。

new Foo<A>(A::new); 

には反射と関係なし例外処理はありません。

も参照してください。this回答。

関連する問題