抽象继承和泛型(带扑克牌)

时间:2009-03-18 00:25:35

标签: java generics inheritance abstract

所以,我一直在研究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 个答案:

答案 0 :(得分:3)

我认为你最大的问题是你只是在没有任何实际要求的情况下创建这些类。遗产真的是正确的选择吗?感觉就像你正在设计类以适应预先设想的实现,而不是相反。

根据实际需求为您需要的每个类定义接口,实现它们,然后查看抽象基类是否有意义。

答案 1 :(得分: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);
    } 
}

您可能需要对声明进行一些处理,但这应该看得出来

答案 2 :(得分:0)

我会给出一个快速的(hackish?)答案:你可以做的是在基类protected abstract Collection<Card> createCollection()中定义CardSet方法。您的子类将覆盖它以创建并返回适合该子类的任何类型的集合。然后超类构造函数将使用该方法创建集合,之后它可以继续并添加卡:

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

答案 3 :(得分: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 {
...
}

这里的cardSets是不同种类的。 Thery是分开的,因为它们的行为方式不同,并且代表了这些类型的集合从卡集的广义概念中获得的额外行为。试图将额外的代码插入到抽象父级中可能会节省几行但最终会产生obfusactes。