如何最好地使用Interfaces / Generics来实现此Card / Deck示例

时间:2015-11-03 10:52:45

标签: c# generics interface dependency-injection

我正在学习泛型/使用依赖注入/接口以便松散耦合类 - 但是,我正在努力。

对于以下简单的卡/卡片示例,我怎样才能最好地调整这些类(使用上述技术),以便我可以传递任何类型的“卡/ ICard”列表,以便能够填充/打印Deck说的类型。因此,例如,在Main中,我希望能够传入List或List,并且对于deck来说能够处理这种方式。

Deck.cs

public class Deck
{
    List<Card> cards;

    public Deck(List<Card> cards)
    {
        this.cards = cards;

        foreach (Card.Suit suit in Enum.GetValues(typeof(Card.Suit))) {
            foreach (Card.Val value in Enum.GetValues(typeof(Card.Val))) {
                cards.Add(new Card(suit, value));
            }
        }
    }


    public void printDeck()
    {
        foreach(Card x in cards)
        {
            Console.WriteLine(x.ToString());
        }
    }
}
}

Card.cs

public class Card : ICard {
    Suit suit;
    Val value;

    public Card(Suit suit, Val value)
    {
        this.suit = suit;
        this.value = value;
    }

    public override string ToString()
    {
        string formatCard = "Suit: " + suit + " Value: " + value;
        return formatCard;
    }

    public enum Suit
    {
        HEARTS = 1,
        SPADES = 2,
        CLUBS = 3,
        DIAMONDS = 4

    }

    public enum Val
    {
        ONE = 1,
        TWO = 2,
        THREE = 3,
        FOUR = 4,
        FIVE = 5
    }
}  
}

SpecialCard.cs

public class SpecialCard : ICard{
    Suit suit;
    Val val;

    public SpecialCard(Suit suit, Val val)
    {
        this.suit = suit;
        this.val = val;
    }

    public override string ToString()
    {
        string formatCard = "Dragon: " + suit + " Value: " + val;
        return formatCard;
    }
    public enum Suit
    {
        RIDGEBACK = 1,
        FIREBALL = 2,
        SHORTSNOUT = 3,
        HORNTAIL = 4

    }

    public enum Val
    {
        UNO = 1,
        DOS = 2,
        TRES = 3,
        QUATTRO = 4,
        CINCZ = 5
    }
}   
}

ICard.cs

public interface ICard
{
    string ToString();
}

主要

static void Main()
    {
        Deck deck = new Deck(new List<Card>());
        deck.printDeck();
        Console.ReadKey();
    }

感谢您的任何指示! FYP

1 个答案:

答案 0 :(得分:1)

我不会把这个套装和价值作为枚举,因为它很难替代不同的实现。一般来说,我会从提供逻辑的类中分离出持有卡片或卡片等状态的类,例如卡片生成器。

我认为你在ICard中不需要ToString(),因为所有类都继承System.Object,它实现了ToString()。无论如何,我不认为卡应该知道它自己的长描述。为什么不让客户根据可用的信息(适合,价值)来决定。

鉴于两种类型的卡的实现是相同的,我只有一个逻辑非常少的类。套装和价值现在可以只是一个字符串,因为您所做的只是打印值。如果您需要稍后比较卡的强度,您可能希望将Value更改为具有int值和字符串描述的类。

public class Card
{
    public string Suit { get; set; }
    public string Value { get; set; }
}
然后,您的套牌将成为卡片清单和所用套装的类型,并将其自身的建筑物委托给其他地方,以避免违反关注点。

public class Deck
{
    public IEnumerable<Card> Cards { get; set; }
    public string SuitName { get; set; }
}

然后你的大部分逻辑将存在于甲板构建器中。为了使客户能够知道要构建哪个套牌,我将创建一个枚举。

public enum DeckType
{
    Standard,
    Special
}

并且构建器将是(静态,因为它没有状态)

public static class DeckBuilder
{
    public Deck Build(DeckType deckType)
    {
        var deck = new Deck();
        switch (deckType)
        {
            case DeckType.Standard:
                deck.SuitName = "Suit";
                deck.Cards = CreateStandardCards();
                break;
            case DeckType.Special:
                deck.SuitName = "Dragon";
                deck.Cards = CreateSpecialCards();
                break;
            default:
                throw new ArgumentException("deckType");
        }
    }

    private IEnumerable<Card> CreateStandardCards()
    {
        var suits = new List<string> { "Hearts", "Clubs", "Diamonds", "Spades"  };
        var values = new List<string> { "One", "Two", "Three", "Four", "Five" };
        return CreateCards(suits, values);
    }

    private IEnumerable<Card> CreateSpecialCards()
    {
        var suits = new List<string> { "Ridgeback", "Fireball", "Shortsnout", "Horntail"  };
        var values = new List<string> { "Uno", "Dos", "Tres", "Quattro", "Cincz" };
        return CreateCards(suits, values);
    }

    private IEnumerable<Card> CreateCards(IEnumerable<string> suits, IEnumerable<string> values)
    {
        foreach (var suit in suits)
        foreach (var value in values)
            yield return new Card { Suit = suit, Value = value };
    }
}

这种方法的替代方法是创建一个IDeckBuilder,它具有StandardDeckBuilder和SpecialDeckBuilder的不同实现,这意味着不需要枚举。如果switch语句变大(例如,如果添加了更多依赖于deck类型的属性),我会这样做。

客户端需要调用相应的构建器。我也会在这里移动printDeck逻辑。甲板类不应该知道如何打印。它不应该知道输出进入控制台。

static void Main()
{
    var deck = DeckBuilder.Build(DeckType.Standard);
    foreach (var card in deck.Cards)
        Console.WriteLine(deck.SuitName + ": " + card.Suit + " Value: " + card.Value);
    Console.ReadKey();
}

我没有尝试过,所以可能无法编译 - 这是我将使用的整体设计的例证。