我认为我的问题主要是语法,但可能是我对类层次结构的整体理解。基本上它是一个带有Card对象的数组的Deck类,Card是Deck的子类,所以Deck应该能够使用Card的块和方法,对吧?如果是的话,我正在搞乱语法,试图调用它。我使用嵌套的while循环来填充数组,但我希望Card对象的每个实例都具有该卡的套装和等级,而不是仅仅打印“一张卡”。我离开了我试图使Card对象成为另一个大小为2的数组以保持Suit和Rank,但是我的gst编译器说它期望一个“对象”,所以很明显我做错了。我粘贴了我的代码,以便您可以看到我在说什么。除了块调用之外,它使用空白卡对象填充大小为52的数组,因此Deck类的其余部分基本上正在工作。
"The Deck object class is a deck of 52 Card objects. "
Object subclass: Deck [
| Content |
<comment: 'I represent of Deck of Cards'>
Deck class >> new [
<category: 'instance creation'>
| r |
r := super new .
Transcript show: 'start ' .
r init .
^r
]
init [
<category: 'initialization'>
|a b c|
Content := Array new: 52 .
a := 1 .
c := 1 .
[a <= 4] whileTrue:[
b := 1 .
[b <= 13] whileTrue:[
|card|
card := Card new .
Card := Array new: 2 . "This is where I'm trying to use the Card class blocks to make the Card objects have Rank and Suit"
Card at: 1 put: Card setRank: b| . "and here the rank"
Card at: 2 put: Card getSuit: a| . "and the suit"
Content at: c put: card .
b := b + 1 .
c := c + 1 .
].
a := a + 1 .
].
Content printNl .
]
] .
"The Card object has subclass Suit and a FaceValue array of Suit and Rank. "
Object subclass: Card [
| Suit Rank |
<comment: 'I represent a playing Card' >
init [
<category: 'initialization'>
Suit := Club .
Rank := 1 .
Transcript show: 'nCard ' .
^super init
]
getSuit: suitVal [
suitVal = 1 ifTrue: [Suit := Club] .
suitVal = 2 ifTrue: [Suit := Diamond] .
suitVal = 3 ifTrue: [Suit := Heart] .
suitVal = 4 ifTrue: [Suit := Spade] .
^Suit
] "getSuit"
setRank: rankVal [
Rank := rankVal .
^Rank
]
]
z := Deck new .
编辑一次 - 由于联邦公司的评论
欢迎来到SO。
免责声明:我使用的是Smalltalk / X-jv分支,它与gnu-smalltalk不同,因此我不是gnu-smalltalk专家。
我会指出你发现的一些不足之处。有太多要指出的。我会给你一些一般性的想法。
a
,b
,c
... z
作为变量。如果您在一段时间后返回代码,您将无法理解它。content
而不是Content
。第一个大写字母保留给全局变量。在您的用例中,这将是一个类名(不要混用它)。aCard := Card new.
#init
(初始化)方法中创建整个应用程序逻辑!你应该用小巧,可读的方法来破解你的代码。你的init应该看看这些方面:
Deck extend [
init [
<category: 'initialization'>
content := Array new: 52.
Transcript show: 'Initializing Deck...'.
]
]
这将使用实例变量#init
创建content
方法。不要忘记为变量创建访问器。阅读guide以获取gnu-smalltalk并创建实例方法。
whileTrue:
循环有意见。为什么有人猜出限制的原因?
[a <= 4] whileTrue:[
b := 1 .
[b <= 13] whileTrue:[
...
new
消息。 Transcript
消息可以是ini init
:
Deck class >> new [
<category: 'instance creation'>
| r |
r := self new .
Transcript show: 'start '.
r init .
^r
]
你为什么重新定义新的?如果你有一个Object subclass:
的对象,那么它已经理解了new
消息。
在你的代码的底部你有z := Deck new.
(我建议使用例如myDeck := Deck new.
)。如果你想运行初始化,你会很简单地做myDeck init
。
Card >> init
返回^super init
?也许你想做第一行super init
(读取\加载超类初始化)然后返回^ self
?很难说。Suit := Club .
这是什么意思?你在某种程度上创造一个新的对象? (缺少#new
消息)。你想要一个字符串吗?那应该是suit := 'Club'.
。 (同样适用于所有Sunit
变量分配)。更多的只是阅读水晶球。尝试阅读有关Smalltalk的更多信息,我希望我的提示可以帮助您在路上。
稍微纠正:你不调用一个块,你调用一个方法。
您提交的代码中的唯一块是whileTrue的参数:并且是方法的私有(不能从外部访问)。
这种困惑不是你的错。这是由于此文件格式用于描述方法的块表示法。在个人情况下,我不喜欢它,我觉得它更有用而不是有用(除了为了看起来更像主流语言,对基于文件的语言的致敬)。
那么你如何调用一个方法呢?你通过发送消息来做到这一点,没有别的办法。您所能做的就是发送消息。 Smalltalk是面向消息的。它的消息一直在下降。
接收消息时,对象将在其类方法字典中查找消息选择器。如果没有,它将在超类等中查找......但这是对象自己的业务。
所以最后,你并没有真正考虑调用方法,因为不同的对象可以用不同的方法响应同一个消息。您必须考虑将任务委托给专门的对象,即消息和相关合同。
那么合同是什么?你想要一张卡片(俱乐部,锹,......)和一个等级(1到13)。所以你用这两个实例变量创建了一个Card类。到现在为止还挺好。
然后你想创建你的52张牌来填补牌组。这是实例化Card类。你是怎样做的?您已将消息new
发送到Card类。您可以创建一个更合适的类消息,它将充当Card构造函数,给定一个套装和一个等级。
那会是这样的
Card class >> newWithSuit: aSuit rank: anInteger
[<category: 'instance creation'>
^self basicNew setSuit: aSuit rank: anInteger ]
setSuit: aSuit rank: anInteger
[<category: 'private'>
suit := aSuit.
rank := anInteger ]
然后你不需要在代码中定义单独的setter(getSuit:
and setRank:
),因为你可能不想在之后更改这些属性,除非在构造时。这就是为什么我通常更喜欢一个单独的安装者,我将其归类为“私人”。这只是一个惯例,但这就是我们如何定义Smalltalk中的契约,通过一组非正式约定,以及通过方法和类注释(以及SUnit TestCase,特别是如果您接受测试驱动设计)。
你决定用1到13的整数编码。这没关系。但你还必须决定如何代表诉讼。在你的代码中不清楚,因为有一个Integer(1到4)和未声明的变量(Club,Spade,...)的混合。这些全局变量?
然后你不必编码那些套装并在大小为2的数组中排名,这绝对是不必要的,因为所有这些数据都已包含在Card对象中。所以你要填写甲板:
content at: deckRank put: (Card newWithSuit: suitNumber rank: rankNumber).
注意括号:你发送消息at:put:
到content
有两个参数,deckRank
和另一个消息返回的值发送(Card newWithSuit: suitNumber rank: rankNumber)
,我们期望它是一个正确初始化的Card实例。
在您提供Card at: 1 put: Card setRank: b
的代码中,您向类at:put:setRank:
发送消息Card
,其中包含3个参数,整数文字1,类Card
和变量b
指向的对象。这可能不是你的意图。在|
之后还有一个b
吧,这对我来说看起来不是一个正确的语法。条形图用于描述临时变量,或者将块参数与块内的块指令分开,或者也可以是二进制消息,但在这种情况下需要参数(每个二进制消息如+ - * /都有接收器和参数)。
我希望我给你一些有用的提示,但也许你必须阅读并应用一些逐步的Smalltalk教程,以便更好地了解这些基本概念。