在 Smalltalk 中,您通常实现#printOn:并#asString从它的继承版本中获取
Object >> asString
| stream |
stream := '' writeStream.
self printOn: stream.
^stream contents
此方法的实际实现在您的环境中可能会略有不同,但思路保持不变。
由于这是给定的,因此实施#printOn:而不是#asString. 在您的情况下,您可以将其实现为
Element >> printOn: aStream
aStream
nextPutAll: 'Element with width ';
nextPutAll: width asString;
nextPutAll: ' and height ';
nextPutAll: height asString
然后,正如 JayK 和 luker 所指出的,
Element >> asDescription
^self asString
换句话说,您(通常)不想实现#asStringbut #printOn:. 这种方法更好,因为它利用了继承并确保了 和 之间的一致性#printOn:,#asString这通常是预期的。此外,它会让您有机会开始熟悉Streams在 Smalltalk 中发挥核心作用的 .
请注意,在我的实现中,我使用了width asStringand heigh asString。您的代码尝试将 aString与 a连接(两次) Number:
'Element with width ', width, ' and height ', height.
这不起作用,因为您只能连接Stringwith的实例#,。
但是,在大多数方言中,您可以#asString通过使用#print:而不是来避免发送#nextPutAll:,例如:
Element >> printOn: aStream
aStream
nextPutAll: 'Element with width ';
print: width;
nextPutAll: ' and height ';
print: height
这有点不那么冗长,因此是首选。
最后一件事。我建议用这个更改上面的第一行:
nextPutAll: self class name;
nextPutAll: ' with width ';
而不是硬编码类名。如果将来您子类化,这将被证明是有用的,Element因为您将无需调整#printOn:及其任何派生类(例如,#asDescription)。
最后的想法:我会将选择器重命名#asDescription为#description. 介词as旨在将一个对象转换为另一个不同类的对象(这就是为什么#asString可以)。但这里的情况似乎并非如此。
附录:为什么?
#asString用来实现是有原因的#printOn:,而不是相反:generality。虽然努力(代码复杂性)是相同的,#printOn:但显然是赢家,因为它适用于任何字符Stream。特别是,它无需任何修改即可使用
- 文件(的实例
FileStream)
- 套接字(的实例
SocketStream)
- 这
Transcript
换句话说,通过实现免费#printOn:获取#asString(继承)和——同时——将对象的表示转储到文件和套接字上的能力。这Transcript特别有趣,因为它支持Stream写入协议,因此可以在向外部设备发送任何字节之前用于测试目的。
记住!
在 Smalltalk 中,目标是同时拥有行为简单且通用的对象,而不仅仅是简单!