在 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
换句话说,您(通常)不想实现#asString
but #printOn:
. 这种方法更好,因为它利用了继承并确保了 和 之间的一致性#printOn:
,#asString
这通常是预期的。此外,它会让您有机会开始熟悉Streams
在 Smalltalk 中发挥核心作用的 .
请注意,在我的实现中,我使用了width asString
and heigh asString
。您的代码尝试将 aString
与 a连接(两次) Number
:
'Element with width ', width, ' and height ', height.
这不起作用,因为您只能连接String
with的实例#,
。
但是,在大多数方言中,您可以#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 中,目标是同时拥有行为简单且通用的对象,而不仅仅是简单!