Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 抽象继承和泛型(带扑克牌)_Java_Generics_Inheritance_Abstract - Fatal编程技术网

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

Java 抽象继承和泛型(带扑克牌),java,generics,inheritance,abstract,Java,Generics,Inheritance,Abstract,所以,我一直在用Java编写一些扑克牌。(其实不是为了任何实际目的,我只是喜欢打牌,它们是很好的练习)现在,现在,我正在制作一些纸牌结构、牌组、手牌、牌堆等。它们基本上都是一样的,所以我想使用一些继承 我遇到的问题是,每个结构的核心都是某种类型的集合,但它们并不都使用相同的集合类型。deck使用堆栈,因为deck最常用于堆栈。但是,一只手使用ArrayList(如果有比ArrayList更有效的东西可以使用,那么最好也知道)。 因此,在尝试编写抽象类时,我希望避免使用抽象方法(因为它违背了创建抽

所以,我一直在用Java编写一些扑克牌。(其实不是为了任何实际目的,我只是喜欢打牌,它们是很好的练习)现在,现在,我正在制作一些纸牌结构、牌组、手牌、牌堆等。它们基本上都是一样的,所以我想使用一些继承

我遇到的问题是,每个结构的核心都是某种类型的集合,但它们并不都使用相同的集合类型。deck使用堆栈,因为deck最常用于堆栈。但是,一只手使用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);
     } 
}
公共抽象类卡片集
{
受保护的抽象集合;
公共卡套()
{
超级();
}
公共卡套(卡[]卡)
{
超级();
用于(卡c:卡)
添加(c);
}
公共无效添加(卡c)
{
添加(c);
}
}
公共类Pair扩展了CardSet//Pair只是一个获得正确继承的伪类
{
ArrayList-elPair;
公共对()
{
elPair=new ArrayList();//定义了elPair,因为
elCollection=elPair;//elCollection到arraylist会很痛苦。
}
公共对(卡[]卡)
{this();
超级卡;
} 
}
首先,请原谅我的变量名。我以前把所有东西都命名为“theVariable”,但我觉得使用“el”更有趣。(你一定要自娱自乐,对吧?)

现在,一般的想法似乎是可行的,在抽象类中定义一个变量,然后在子类中定义它的别名,但我不确定这是否是一个好的实践。 我遇到的真正问题是构造函数。接受卡片数组的成对构造函数不起作用,因为要添加卡片,首先需要创建 在父构造函数尝试添加卡之前收集(在本例中为ArrayList)。
有办法解决这个问题吗?这是处理继承的可行方法吗

只需让每个实现在构造函数中传递集合类型:

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);
    } 
}
公共抽象类卡片集
{
受保护的最终收集;
公共卡套卡套()
{
返回新的卡片集(new ArrayList());
}
公共卡组(C列){
this.elCollection=col;
}
公共卡组(C列,卡[]卡)
{
这个(col);
用于(卡c:卡)
添加(c);
}
公共无效添加(卡c)
{
添加(c);
}
}
公共类对扩展了CardSet
{
公共对()
{
super(新的ArrayList());
}
公共对(卡[]卡)
{ 
超级(新ArrayList(),卡片);
} 
}
您可能需要对声明进行一点处理,但这应该会让您感觉正确

我会给出一个快速的(hackish?)回答:您可以做的是在基类
CardSet
中定义一个
受保护的抽象集合createCollection()
方法。您的子类将覆盖该类,以创建并返回适合该子类的任何类型的集合。然后超类构造函数将使用该方法创建集合,然后可以继续添加卡片:

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

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

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

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 {
...
}
public类组扩展了CardSet{
公共甲板(){
卡片=新堆栈();
}
public void shuffle(){…}
}
公营手牌{
公职人员(){
//我在这里使用集合,而不是示例中的列表,因为
//不要认为排序是手的特性。
cards=新HashSet();
}
}
公共类对扩展了CardSet{
...
}

这里有不同种类的卡片。它们是分开的,因为它们的行为预期不同,并且代表了这些类型的集合从广义的卡片集概念中所具有的附加行为。试图在抽象父级中插入额外的代码可能会节省几行代码,但最终会造成混淆。

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


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

所以我认为Stephen的答案可能更好。。。但值得一提的是,这是一个设计模式,我已经使用了好几次。我不得不将这个(new ArrayList())更改为这个((C)new ArrayList()),但是我现在因为它而得到了一个“未检查或不安全操作”错误。是的-我已经更新了一个静态工厂,它将