没有,真的。严格来讲,OOP并不能真正解决问题。对于非面向对象的系统,您无法使用面向对象的系统做任何事情-的确,对于图灵机,这是您无能为力的。最终所有这些都变成了机器代码,并且ASM当然不是面向对象的。
OOP范例为您服务的是,它使组织变量和函数变得更加容易,并使您可以更轻松地将它们一起移动。
假设我想用Python编写纸牌游戏。我将如何代表卡?
如果我不了解OOP,可以这样进行:
cards=["1S","2S","3S","4S","5S","6S","7S","8S","9S","10S","JS","QS","KS","1H","2H",...,"10C","JC","QC","KC"]
我可能会写一些代码来生成这些卡,而不是只手工写出来,但是您明白了。“ 1S”代表黑桃1,“ JD”代表钻石杰克,依此类推。我还需要一个小丑代码,但我们只是假装目前没有小丑。
现在,当我想要洗牌时,我只需要“洗”列表即可。然后,要从卡片组顶部取出卡片,我从列表中弹出顶部条目,给我字符串。简单。
现在,如果我想弄清楚我正在使用哪张卡,以便将其显示给玩家,我需要一个像这样的功能:
def card_code_to_name(code):
suit=code[1]
if suit=="S":
suit="Spades"
elif suit=="H"
suit="Hearts"
elif suit=="D"
suit="Diamonds"
elif suit=="C"
suit="Clubs"
value=code[0]
if value=="J":
value="Jack"
elif value="Q":
value="Queen"
elif value="K"
value="King"
return value+" of "+suit
有点大,很长且效率低下,但它可以工作(而且非常不可思议,但这不在这里。)
现在,如果我希望卡片能够在屏幕上移动怎么办?我必须以某种方式存储他们的位置。我可以将其添加到他们的卡代码的末尾,但这可能有点笨拙。相反,让我们再列出每张卡的位置:
cardpositions=( (1,1), (2,1), (3,1) ...)
然后,我编写代码,以使列表中每张卡的位置索引与卡组中卡本身的索引相同。
或者至少应该如此。除非我弄错了。我很可能会这样,因为要处理此设置,我的代码将变得相当复杂。当我想洗牌时,我必须以相同顺序洗牌。如果我将卡完全从甲板上取出怎么办?我也必须把它的位置拿出来,放在其他地方。
如果我想存储有关卡的更多信息怎么办?如果我想存储是否翻转每张卡怎么办?如果我想要某种物理引擎并且还需要知道卡片的速度怎么办?我将完全需要另一个列表来存储每张卡的图形!对于所有这些数据点,我将需要单独的代码来将它们正确地组织起来,以便每张卡都以某种方式映射到其所有数据!
现在让我们尝试这种OOP方式。
让我们定义一个Card类并从中构建Card对象列表,而不是代码列表。
class Card:
def __init__(self,value,suit,pos,sprite,flipped=False):
self.value=value
self.suit=suit
self.pos=pos
self.sprite=sprite
self.flipped=flipped
def __str__(self):
return self.value+" of "+self.suit
def flip(self):
if self.flipped:
self.flipped=False
self.sprite=load_card_sprite(value, suit)
else:
self.flipped=True
self.sprite=load_card_back_sprite()
deck=[]
for suit in ("Spades","Hearts","Diamonds","Clubs"):
for value in ("1","2","3","4","5","6","7","8","9","10","Jack","Queen","King"):
sprite=load_card_sprite(value, suit)
thecard=Card(value,suit,(0,0),sprite)
deck.append(thecard)
现在,突然之间,一切都变得简单了。如果要移动卡,则不必弄清楚卡在卡座中的位置,然后使用该卡将其位置从位置阵列中移出。我只需要说thecard.pos=newpos
。当我从主卡组列表中取出卡时,不必创建新的列表来存储所有其他数据。卡对象移动时,其所有属性都随之移动。而且,如果我想要一张在翻转时行为不同的卡,则不必修改主代码中的翻转功能,以便它检测到这些卡并执行不同的操作;我只需要对Card进行子类化,并在子类上修改flip()函数。
但是如果没有OO,我在那做的事就不可能完成。仅仅是使用一种面向对象的语言,该语言正在为您完成将事物保持一致的许多工作,这意味着您犯错误的机会要少得多,并且代码更短,更容易阅读和编写。
或者,总而言之,OO通过隐藏很多处理数据的常见复杂性,使您可以编写看起来更简单的程序,与更复杂的程序执行相同的工作。