我正在通过Chris Pine的'Learn to Program'学习Ruby。我试图应付没有全局变量。我有一个看起来很邋遢的命令提示21点程序(还不能分割)。我的前三个方法说明了我遇到的问题。在Pascal中,我会使用全局变量,并使用方法来操作这些全局变量。它看起来像这样(使用ruby伪语言)
$deck_of_cards = []
$player_hand = []
$dealer_hand = []
def create_deck
$deck_of_cards = #numbers 1-52
end
def shuffle_deck
$deck_of_cards = #shuffled up deck of cards
end
def opening_deal
2.times do
$player_hand.push $deck_of_cards.pop
$dealer_hand.push $deck_of_cards.pop
end
end
create_deck
shuffle_deck
opening_deal
我最终会得到一张洗牌牌,一张玩家手牌和一张发牌手牌。去掉全局变量,前两个方法现在看起来像这样:
def create_deck deck_of_cards
deck_of_cards = #numbers 1-52
return deck_of_cards
end
def shuffle_deck deck_of_cards
deck_of_cards = #shuffled up deck of cards
return deck_of_cards
end
deck = create_deck([])
deck = shuffle_deck(deck)
感觉有点奇怪,但我可以习惯它。
但我完全卡住了最后一个方法,这需要返回两个变量,player_hand和dealer_hand。我可以把这两个数组放到另一个数组中,然后返回,但这看起来并没有简化任何东西。
是否有一个通用的策略来处理这种情况,或者每种情况都有自己独特的解决方案?
我想到的另一种情况是一个国际象棋程序。既然象棋程序中的几乎所有方法都需要使用它的值,为什么将棋盘作为全局变量没有意义呢?简短的回答:对象。面向对象编程允许封装数据,这样数据就不会污染全局命名空间。随着项目规模的扩大,将所有数据放在全局名称空间中变得不可维护。对象允许您将数据和方法分组为有意义的单元,然后可以更容易地重用和维护。
以你提供的例子为例,我们可以制作deck和hand对象。这允许我们轻松地创建多个deck和hand,因为这些对象封装和管理它们的数据。
作为如何组织类/方法的粗略大纲:
class Deck
def shuffle
end
def draw_hand
end
end
class Hand
end
class Card
end
一般来说,使用面向对象编程技术,您将定义类并创建这些类的对象,然后传递这些对象。你可以把对象想象成数组,因为它们可以包含很多相关的数据,但比数组更好的是,数据元素可以有名字,可以是任何类型,而不需要是相同的类型,它们带有命名函数来操作数据。(实际上,在Ruby中,数组元素可以是任何类型,不需要是相同的类型,Hash元素也是如此,而且Hash元素有名称,但Ruby在这方面很特殊。)
保持简单,你可以像这样继续你的程序:
def opening_deal deck_of_cards
player_hand = []
dealer_hand = []
2.times do
player_hand.push deck_of_cards.pop
dealer_hand.push deck_of_cards.pop
end
return player_hand, dealer_hand
end
player_hand, dealer_hand = opening_deal deck
使用全局变量是一个坏习惯,但是使用全局常量并不是坏事,或者换句话说,在主名称空间中定义常量。当需要全局变量时,您总是可以在主名称空间中定义常量。可变对象,如字符串,散列,数组可以修改,即使它是一个常量。如果这还不够,你需要更复杂的东西,那么你可以定义一个模块(这是常量的特殊情况),并在该模块上定义方法来访问你想做的事情,并使用实例变量将复杂的信息封装在该模块中。