一种使 类 用于比标准牌组中更复杂的纸牌类型的好方法?

A good way to make classes for more complex playing card types than those found in a standard deck?

我是面向对象编程的新手,我正尝试通过制作一个简单的纸牌游戏(似乎很传统!)来开始学习 python。我已经完成了以下工作正常的示例,并教我如何制作 PlayingCard() class 的多个实例来创建 Deck() class:[=19= 的实例]

class PlayingCard(object):
    def __init__(self, suit, val):
        self.suit = suit
        self.value = val

    def print_card(self):
        print("{} of {}".format(self.value, self.suit))

class Deck(object):
    def __init__(self):
        self.playingcards = []
        self.build()

    def build(self):
        for s in ["Spades", "Clubs", "Diamonds", "Hearts"]:
            for v in range(1,14):
                self.playingcards.append(PlayingCard(s,v))

deck = Deck()



我现在想用更复杂的卡片制作一些东西,而不仅仅是标准的 52 副牌(它具有很好的增量值)。我想到的套牌是大富翁纸牌游戏:

卡片有 3 种基本类型 - 行动卡片、属性 卡片和金钱卡片。行动牌执行不同的行动,属性张牌属于不同的颜色组,金钱牌可以有不同的价值。此外,属性 卡片可以是 "wildcards",并且可以用作两个集合之一的一部分。最后,每张卡还具有等值的货币价值(标示在每张卡的顶角)。在租用行动卡中,该卡只能适用于卡上指示的颜色属性。

我的问题只是通常如何处理这种情况,以及将这些不同的卡片包含在基于 class 的 python 程序中的好方法是什么?我应该保留我的单身 PlayingCard() class,并且只有很多输入,例如 PlayingCard(type="PROPERTY", value="3M")。或者创建单独的 class 会更好,例如 ActionPlayingCard()PropertyPlayingCard() 等?或者,还有更好的方法?就像我说的,我刚刚开始学习,以及如何根据更高层次的设计来组织这些类型的情况。

非常感谢。

这些就是我们所说的"design decisions"。通常 "correct" 方式见仁见智。作为初学者,我认为尝试这两种实现以了解它们的工作原理会很有启发。无论您选择哪一个,都会有取舍。您必须决定哪些权衡是最重要的。随着您获得更多经验,您会做出这些决定。

您可以使用继承。 这是您创建主 class 然后有子 class 的地方,它仍然包含来自母亲 class 的函数和值,但是也可以为特定的 [=16] 提供额外的值和函数=].

class Apple:
    def __init__(self, yearMade):
        pass

    def ring(self):
        print('ring ring')

class iPhone(Apple):
    def __init__(self, number)
        number = number

    def func():
        pass

现在iPhoneclass和苹果class一样的功能,还有自己的功能。 如果您想了解有关继承的更多信息,我建议您做一些研究。

对于垄断,我会设计游戏登陆的角度。不是卡片。卡片只是代表现实世界的着陆点。

当您使用 OOP 解决问题时,您通常希望以可重用的方式对行为和属性进行建模,即,您应该考虑抽象并组织您的 class 层次结构基于此。

我会这样写:

class Card:
    def __init__(self, money_value=0):
        self.money_value = money_value

class ActionCard(Card):
    def __init__(self, action, money_value=0):
        super().__init__(money_value=money_value)

        self.action = action

class RentActionCard(ActionCard):
    def __init__(self, action, color, money_value=0):
        super().__init__(action, money_value=money_value)

        self.color = color

    def apply(self, property_card):
        if property_card.color != self.color:
            # Don't apply
        # Apply

class PropertyCard(Card):
    def __init__(self, color, money_value=0):
        super().__init__(money_value=money_value)

        self.color = color

class WildcardPropertyCard(PropertyCard):
    def __init__(self, color, money_value=0):
        super().__init__(color, money_value=money_value)

class MoneyCard(Card):
    def __init__(self, money_value=0):
        super().__init__(money_value=money_value)


由于 Python 是一种动态类型的语言,OOP 在我看来有点难以证明,因为我们只能依靠 duck typingdynamic binding, 您组织层次结构的方式不太重要。

例如,如果我要在 C# 中对这个问题建模,我毫无疑问会使用上面显示的层次结构,因为我可以依赖 多态性 来表示不同的类型并根据正在分析的卡片类型指导我的逻辑流程。

最后几点:

  1. Python 具有非常强大的内置类型,但大多数时候 使用基于它们构建的新自定义类型让您的生活更轻松。
  2. 您不必从 object 继承,因为在 Python 3 中输入(这是 截至今天唯一维护的)默认继承自 object

但是,归根结底,没有一个完美的答案,最好的方法是尝试这两种方法,看看您更喜欢哪种方法。