在 Pharo 或 Smalltalk 中制作构造函数
making a constructor in Pharo or Smalltalk
我想在 Pharo 中实现一个小的 class,所以我这样做了:
Object subclass: #Person
instanceVariableNames: 'name age'
classVariableNames: ''
category: 'Test'
我想模拟一个构造函数,所以我做了一个如下所示的方法:
newName:aName newAge:aAge
"comment stating purpose of message"
name:=aName.
age:=aAge.
^self.
但是当我想像这样从 Pharo 的游乐场调用它时:
objPerson:=Person newName:'Carl' newAge: 10.
Pharo 无法识别,我做错了什么?
表达式 Person newName: 'Carl' newAge: 10
是给 class 对象 Person
的消息。因此,您必须在 Person
.
的 class 端实施它
您的代码需要像这样调整
Person class >> newName: aName newAge: anAge
| person |
person := self new.
person name: aName.
person age: anAge.
^person
注意上面代码中self
指的是class,因为方法是在class这边。但是由于 person
是 Person
的实例,消息 name: aName
和 age: anAge
必须在实例端定义。
因此,在实例端,需要添加两个setter:
Person >> name: aString
name := aString
Person >> age: anInteger
age := anInteger
使用这三种方法,您应该能够 运行 您的示例。
关于编码风格的一些补充意见:
首先,我会为 "constructor" 方法选择一个不同的选择器(在 Smalltalk 中我们称这些为 "instance creation" 方法)。例如,
Person class >> named: aString age: anInteger
^self new name: aString; age: anInteger
其次,不需要为新创建的实例使用临时 person
,因为表达式 self new
已经引用了这样一个实例。
最后,注意
中级联语法的使用
^self new name: aString; age: anInteger
这意味着消息 age: anInteger
将被发送到与 name: aString
相同的接收者,在这种情况下恰好是 self new
.[=27 返回的新实例=]
虽然大体上我同意 Leandro 的回答,它向私有属性公开了访问器。
Kent Beck 在他的 Smalltalk Best Practice Patterns(我强烈推荐)中建议使用 set
作为实例端构造函数的前缀,例如:
"add to class side to 'instance creation' protocol"
Person>>class name: aName age: anAge
^ self new
setName: aName age: anAge;
yourself
"add to instance side to 'initialization' protocol"
Person>>setName: aName age: anAge
name := aName.
age := anAge.
这样您就可以控制是否公开属性。
或者您可以坚持原来的命名方式,只添加您忘记的 new
。
objPerson := Person new newName:'Carl' newAge: 10.
我想在 Pharo 中实现一个小的 class,所以我这样做了:
Object subclass: #Person
instanceVariableNames: 'name age'
classVariableNames: ''
category: 'Test'
我想模拟一个构造函数,所以我做了一个如下所示的方法:
newName:aName newAge:aAge
"comment stating purpose of message"
name:=aName.
age:=aAge.
^self.
但是当我想像这样从 Pharo 的游乐场调用它时:
objPerson:=Person newName:'Carl' newAge: 10.
Pharo 无法识别,我做错了什么?
表达式 Person newName: 'Carl' newAge: 10
是给 class 对象 Person
的消息。因此,您必须在 Person
.
您的代码需要像这样调整
Person class >> newName: aName newAge: anAge
| person |
person := self new.
person name: aName.
person age: anAge.
^person
注意上面代码中self
指的是class,因为方法是在class这边。但是由于 person
是 Person
的实例,消息 name: aName
和 age: anAge
必须在实例端定义。
因此,在实例端,需要添加两个setter:
Person >> name: aString
name := aString
Person >> age: anInteger
age := anInteger
使用这三种方法,您应该能够 运行 您的示例。
关于编码风格的一些补充意见:
首先,我会为 "constructor" 方法选择一个不同的选择器(在 Smalltalk 中我们称这些为 "instance creation" 方法)。例如,
Person class >> named: aString age: anInteger
^self new name: aString; age: anInteger
其次,不需要为新创建的实例使用临时 person
,因为表达式 self new
已经引用了这样一个实例。
最后,注意
中级联语法的使用^self new name: aString; age: anInteger
这意味着消息 age: anInteger
将被发送到与 name: aString
相同的接收者,在这种情况下恰好是 self new
.[=27 返回的新实例=]
虽然大体上我同意 Leandro 的回答,它向私有属性公开了访问器。
Kent Beck 在他的 Smalltalk Best Practice Patterns(我强烈推荐)中建议使用 set
作为实例端构造函数的前缀,例如:
"add to class side to 'instance creation' protocol"
Person>>class name: aName age: anAge
^ self new
setName: aName age: anAge;
yourself
"add to instance side to 'initialization' protocol"
Person>>setName: aName age: anAge
name := aName.
age := anAge.
这样您就可以控制是否公开属性。
或者您可以坚持原来的命名方式,只添加您忘记的 new
。
objPerson := Person new newName:'Carl' newAge: 10.