在Pharo或Smalltalk中创建构造函数
我想在Pharo中实现一个小类,所以我做了以下工作:在Pharo或Smalltalk中创建构造函数,smalltalk,pharo,Smalltalk,Pharo,我想在Pharo中实现一个小类,所以我做了以下工作: Object subclass: #Person instanceVariableNames: 'name age' classVariableNames: '' category: 'Test' 我想模拟一个构造函数,所以我制作了一个如下的方法: newName:aName newAge:aAge "comment stating purpose of message" name:=aName.
Object subclass: #Person
instanceVariableNames: 'name age'
classVariableNames: ''
category: 'Test'
我想模拟一个构造函数,所以我制作了一个如下的方法:
newName:aName newAge:aAge
"comment stating purpose of message"
name:=aName.
age:=aAge.
^self.
但当我想在法罗的操场上这样称呼它:
objPerson:=Person newName:'Carl' newAge: 10.
Pharo不认识它,我做错了什么?表达式
Person newName:'Carl'newAge:10
是给类对象Person
的消息。因此,您必须在Person
的类端实现它
您的代码需要像这样进行调整
Person class >> newName: aName newAge: anAge
| person |
person := self new.
person name: aName.
person age: anAge.
^person
请注意,在上面的代码中,self指的是类,因为方法位于类一侧。但是由于person
是person
的实例,因此必须在实例侧定义消息name:aName
和age:anAge
因此,在实例端,您需要添加两个setter:
Person >> name: aString
name := aString
Person >> age: anInteger
age := anInteger
使用这三种方法,您应该能够运行您的示例
关于编码样式的一些附加注释: 首先,我会为“构造函数”方法选择一个不同的选择器(在Smalltalk中,我们称这些方法为“实例创建”方法)。比如说,
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
返回的新实例,尽管我大体上同意Leandro的回答,它将访问者暴露于私有属性。
Kent Beck在他的Smalltalk最佳实践模式(我极力推荐)中建议使用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.
通过这种方式,您可以控制是否公开属性
或者你可以坚持你原来的命名,只添加你忘记的新的
objPerson:=Person newName:'Carl'newAge:10。
这一点很好。但是,我会使用#name:age:
选择器而不是#setName:age:
。其他语言需要在setter和getter前面加上set
或get
,因为它们没有其他方法来区分它们。在Smalltalk中,冒号是选择器的一部分,然后使用这些前缀就变得多余了。@LeandroCaniglia这正是它加前缀的原因-以区别于常规setter(不加前缀)。您不需要再次调用此方法。我重视拥有实例端构造函数的想法,以及将它们与常规setter进一步区分开来的想法。但是,我更喜欢传达方法分类的区别,而不是将set
附加到选择器。使用set
作为前缀是不好的,因为这只是一种隐藏事实的方式,即您除了。。。设置变量。在这种情况下,我会使用#initializeName:age:作为选择器。。。然后你可以这样做:#name:aName-age:aNumber^self-basicNew-initializeName:aName-age:aNumber。
总之,这只是一个关于风格的讨论,而不是最重要的问题(问题本身)。。。所以我认为Leandro和Peter的回答都是正确的:)