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

我会给出一个快速(hackish?)的答案:你可以做的是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 回答
0

我在这里的感觉是你试图用继承做两件不同的事情,所以看起来很混乱 -

一方面,你有一套卡片的概念。这将有一组卡片。所以首先我们知道我们有这个:

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 回答