2009-03-18 13 views
2

私はJavaでいくつかのトランプカードに取り組んできました。 (実際には実際の目的ではなく、私はカードを楽しむだけで、彼らは良い練習です)今、今、私はいくつかのカード構造、デッキ、手、杭などを作っています。私はいくつかの継承を使いたいと思っています。要約継承とジェネリックス(トランプ付き)

私が遭遇した問題は、各構造のコアがある種のコレクションであることですが、すべて同じコレクションタイプを使用するわけではありません。デッキは本質的にスタックとして機能するため、スタックを使用します。しかし、手にはArrayListが使用されます(使用するArrayListよりも効率的なものがあれば、同様に知っておくと良いでしょう)。 抽象クラスを書くとき、抽象メソッドの使用を避けたいと思います(コードを節約するために、抽象クラスを作成する本来の目的を破っているので)。しかし、これらのメソッドはすべて、コアコレクションに依存しているのは明らかですが、コレクションの種類はわかりません。これはこれまで私が試したことです:

public abstract class CardSet 
{ 
    protected AbstractCollection<Card> elCollection; 
    public CardSet() 
    { 
     super(); 
    } 
    public CardSet(Card[] cards) 
    { 
     super(); 
     for(Card c: cards) 
      elCollection.add(c); 

    } 
    public void add(Card c) 
    { 
     elCollection.add(c); 
    } 
} 
public class Pair extends CardSet //Pair is just a dummy class to get inheritance right 
{ 
    ArrayList<Card> elPair; 
    public Pair() 
    { 
     elPair = new ArrayList<Card>(); //elPair is defined, because casting 
     elCollection = elPair; // elCollection to arraylist would be a pain. 

    } 
    public Pair(Card[] cards) 
    { this(); 
     super(cards); 
    } 
} 

最初に、私の変数名を許してください。私はすべての "theVariable"という名前を使用していましたが、私は "エル"を使用する方がより興味深いと判断しました。 (あなたは何とか自分自身を楽しまなければなりませんか?)また、protectedを使用するのは、単純化のためです。

一般的な考え方は、抽象クラスで変数を定義し、子クラスでそのエイリアスを定義するように動作しているようですが、それは大したことではありません。 私が持っている本当の問題は、コンストラクタにあります。カードを追加するには、親コンストラクタがカードを追加しようとする前に、最初に コレクション(この場合はArrayList)を作成する必要があるため、一連のカードを受け入れるペアのコンストラクタは機能しません。 これを回避する方法はありますか?これは継承を処理する実行可能な方法ですか?

答えて

2

ただ、各実装はコンストラクタでコレクション型を伝承があります。

public abstract class CardSet<C extends Collection<Card>> 
{ 
    protected final C elCollection; 
    public CardSet<Collection<Card>> cardSet() 
    { 
     return new CardSet<Collection<Card>>(new ArrayList<Card>()); 
    } 
    public CardSet(C col){ 
     this.elCollection = col; 
    } 
    public CardSet(C col, Card[] cards) 
    { 
     this(col); 
     for(Card c: cards) 
      elCollection.add(c); 
    } 
    public void add(Card c) 
    { 
     elCollection.add(c); 
    } 
} 
public class Pair extends CardSet<List<Card>> 
{ 
    public Pair() 
    { 
     super(new ArrayList<Card>()); 

    } 
    public Pair(Card[] cards) 
    { 
     super(new ArrayList<Card>(), cards); 
    } 
} 

あなたが宣言して少しプレイしているかもしれないが、それはあなたの右

+0

この(新しいArrayList ())をこの((C)の新しいArrayList ())に変更する必要がありましたが、これで「未確認または安全でない操作」エラーが発生します。 – Retsam

+0

True - タイプセーフなオブジェクトを返す静的ファクトリを作成するように更新しました。 – Stephen

+0

あなたはリストのジェネリック型を返すようにすることができますが、あなたはオプションを開いたままにしたいと思っています。私は空のコンストラクタを持つことは限られた利益のものであると推測したいと思います(あなたの専門家/コンビニエンスクラスを作成するとき) – Stephen

0

を確認する必要があり、私はあげます迅速な(ハックな?)答え:あなたができることは、CardSetprotected abstract Collection<Card> createCollection()メソッドが基本クラスで定義されていることです。サブクラスはこれをオーバーライドして、そのサブクラスに適したコレクションのタイプを作成して返します。その後、スーパークラスのコンストラクタは、それが先に行くと、カードを追加することができた後、コレクションを作成し、そのメソッドを使用します。ここで

public CardSet(Card[] cards) { 
    super(); 
    self.elCollection = createCollection(); 
    Collections.addAll(self.elCollection, cards); 
} 
+0

スティーブンの答えはおそらくもっと良いと思います...しかし、それは価値がありますデザインパターンは、私のために便利になってきました。 –

0

私の気持ちはあなたが継承して2つの別々の事をやろうとしているということですので、混乱しているようです -

一方では、あなたはカードのセットの概念を持っています。これはカードのコレクションを持っています。あなたのクラスは、私たちがこれまで持っていること(だけでなく、我々は、おそらくにおけるいくつかの追加のメソッドを共通の行動の広がりがありますされているので、発散べきこの時点で

public abstract class CardSet { 
    protected Collection<Card> cards; 
} 

:だから最初、私たちはこのことを知っていますsize()、nextCard()、isEmpty()などのように、保護されたコレクションで定義するのは簡単ですが、今は気にしないでください)。

public class Deck extends CardSet { 
     public Deck(){ 
     cards = new Stack<Card>(); 
    } 

    public void shuffle() { ... } 
} 

public class Hand extends CardSet { 
    public Hand(){ 
     //i'm using a set here instead of the list in your example because I 
     // don't think ordering is a property of a hand. 
     cards = new HashSet<Card>(); 
    } 
} 
public class Pair extends CardSet { 
... 
} 

独自の例を使用するには、ここcardSetsは異なる種類です。 Theryは別々に行動すると予想されるため分離され、これらのタイプのコレクションがカードセットの一般化された概念から持つ追加の動作を表します。抽象的な親に追加のコードを書き込むと、いくつかの行が節約されるかもしれませんが、最終的にはobfusactesです。

+0

私はセットを見ましたが、セットの問題は、あなたが要素を重複させることができないことです。そして、カードは同じスイートと値を持っているかどうか(私の定義では)等しいので、 (複数のデッキを持つゲームをプレイしている場合) – Retsam

3

私はあなたの最大の問題は、本当の必要条件なしにこれらのクラスを作成することだと思います。継承は本当に正しい選択ですか?他の方法ではなく、事前に実装された実装に合わせてクラスを設計するような感じです。

実際の要件に基づいて必要な各クラスのインターフェイスを定義して実装し、抽象基本クラスが適切かどうかを確認します。

+0

まあ、私は抽象的な表現を使用しているのですが、重複したメソッドを再定義する時間がたくさんあります。私たちが現実的であれば、パイルとデッキの違いは何ですか?まあ、パイルは上向きです。それはそれです。 – Retsam

+0

それは私の主張です。あなたが実際に何かをコーディングしていたのであれば、パイルとデッキを別々のクラスにする必要がありますか?私はここで煙を吹くだけではなく、実際にカードとドミノのコードを書いています。私が見つけたのは、あなたが要件に集中していないと、それを上回るのは簡単だということです。 – JohnOpincar

+0

+1です。最初にクライアントコードを書いて、それが必要なメソッドだけを持つインターフェースに依存するようにします。異なる依存関係はおそらく異なるインターフェースを持つでしょう。次に、実際に必要な実装の数を確認できます。 – erickson