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」という名前を付けていましたが、「el」を使用する方が面白いと判断しました。(なんらかの方法で自分を楽しませる必要がありますよね?) また、protected を使用したのは単純化のためでした。

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

4

4 に答える 4

3

あなたの最大の問題は、実際の要件なしでこれらのクラスを作成していることだと思います。ここで継承は本当に正しい選択でしょうか? その逆ではなく、事前に考えられた実装に適合するようにクラスを設計しているように感じます。

実際の要件に基づいて、必要なクラスごとにインターフェイスを定義し、それらを実装してから、抽象基本クラスが適切かどうかを確認してください。

于 2009-03-18T02:40:16.920 に答える
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);
    } 
}

宣言で少し遊ぶ必要があるかもしれませんが、それはあなたを正しく見るはずです

于 2009-03-18T00:35:31.650 に答える
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 {
...
}

ここで、cardSetにはさまざまな種類があります。それらは異なる動作をすることが期待されるため分離されており、これらのタイプのコレクションがカードセットの一般化された概念から持つ追加の動作を表しています。追加のコードを抽象親にシューホーンしようとすると、数行節約できますが、最終的にはわかりにくくなります。

于 2009-03-18T01:45:13.743 に答える
0

簡単な (ハックな?) 答えを出します: できることはprotected abstract Collection<Card> createCollection()、基本クラスでメソッドを定義することですCardSet。サブクラスはこれをオーバーライドして、そのサブクラスに適した任意のタイプのコレクションを作成して返します。次に、スーパークラス コンストラクターはそのメソッドを使用してコレクションを作成し、その後でカードを追加します。

public CardSet(Card[] cards) {
    super();
    self.elCollection = createCollection();
    Collections.addAll(self.elCollection, cards);
}
于 2009-03-18T00:36:18.153 に答える