哪本书最能描述制作自定义构造函数的正确方法?
例如,我想要特殊的文件系统(在RDBMS存储中模拟)。
Object subclass: #C1_Object
C1_Object subclass: #C1_File
instanceVariableNames: 'stream name'
用例:
C1_File new: 'blablabla'
或
C1_File create: 'blablabla'
(1)看起来很原生,但是 我见过建议不要覆盖系统分配机制。
下一步:什么是更好
C1_File class>>create: aFileName
^ self new initialize: aFileName
C1_File>>initialize: aFileName
name := aFileName.
stream := C1_FileStream forceNewFileNamed: aFileName.
或
C1_File class>>create: aFileName
| instance |
instance := super new.
instance name: aFileName.
instance stream: ( C1_FileStream forceNewFileNamed: aFileName ).
^ instance initialize
C1_File>>initialize
^ super initialize
答案 0 :(得分:4)
谁告诉你不要覆盖系统分配机制?
在任何情况下,在这种情况下都不建议覆盖#new:
,因为对于约定#new:使用参数接收大小而不是字符串,因此会令人困惑。
现在,我会使用类似:named:
,newWithName:
等的内容,但这取决于您(是偏好问题)。
有一件事:在Pharo中,如果你instance := self new
以及之后instance initialize
,你将调用初始化两次,因为#new
的默认实现是self basicNew initialize
,所以你的方法需要像这样定义:
C1_File class>>create: aFileName
| instance |
instance := self basicNew.
instance name: aFileName.
instance stream: ( C1_FileStream forceNewFileNamed: aFileName ).
^ instance initialize
但我也不建议这样做(在创作者方法中初始化流感觉不太好)。相反,我会这样做:
C1_File class>>create: aFileName
^ self basicNew
initializeName: aFileName;
yourself.
C1_File>>initializeName: aFileName
self name: aFileName.
self stream: ( C1_FileStream forceNewFileNamed: aFileName ).
self initialize.
答案 1 :(得分:4)
哪本书最能描述制作自定义构造函数的正确方法?
Kent Beck的Smalltalk最佳实践模式(我强烈建议您随时参考)包含大约100个Smalltalk模式,其中也包括
所有这些都讨论了对象创建和参数传递的各个方面,但是共同的主题是增加理解和清晰度(以及意图揭示选择器,这是另一种模式)。
当你有
时C1_File create: 'blablabla'
目前尚不清楚实际会发生什么; C1_File
要创建blablabla
吗?那是什么意思?正如埃斯特班所指出的那样,最好将这个论点命名为...... C1_File named: 'blablabla'
;现在我知道会发生什么。
(1)看起来很原生,但我看到建议不要覆盖系统分配机制。
你必须弄乱#basicNew
来搞乱分配机制。如果你看一下#new
的实现,它实际上并没有做太多。
Behavior>>new
^ self basicNew initialize
系统中还有很多例子:
OrderedCollection with: anItem
Color fromString: '#AC13D9'
或Color r: 0.2 g: 0.5 b: 0.1
Point x: 10 y: 17
on:
.. STONReader on: aReadStream
请注意,开头提到的书不只是展示如何创建基本构造函数,还讨论了实例创建本身的其他问题和挑战(例如,当您有多个不同的构造函数时,不会炸毁您的方法协议等等。)
课程方面与实例方面 - 更多关于Esteban答案的附录:
将班级的常规行为保持在最低限度;类侧主要用于元行为---管理类本身,而不是实际工作。
答案 2 :(得分:0)
除了我在Sqeuak和第三方软件包中看到的Smalltalk代码之外,我没有从头顶引用。像Read-/WriteStream class>>on: aCollection
,Text class>>fromString:
这样的自定义构造函数以它们的参数将在创建的实例中使用的方式进行通信。另一种方式是在构造函数初始化后直接命名构造函数。像Point class>>x:y:
这样的东西。集合构造函数with:
和withAll:
使代码能够流畅地读取。
我总是努力命名构造函数,使得对于发送者的读者变得清楚,你将得到什么作为答案(对该集合进行操作的Stream,具有这些坐标的Point,具有给定的打开的文件)名称/路径?)。我不会覆盖new:
,而create
听起来相当通用,但在谈论文件(打开以进行编写或创建,如果它不存在)时可能很有用,尽管它与FileStream API不同,如据我所知。
否则,仍然有可能不定义构造函数,而是直接在new
之后使用访问器等初始化对象:
MyFileDoesNotExist new
file: c1File;
yourself "or signal in this case"