2

如何让一个类公开具有 2 个不同名称的相同方法?

例如,该asDescripton函数执行相同的操作/重新导出该asString函数,而无需简单地复制粘贴代码。

Object subclass: Element [
  | width height |

  Element class >> new [
    ^super new init.
  ]

  init [
    width := 0.
    height := 0.
  ]

  asString [
    ^ 'Element with width ', width, ' and height ', height.
  ]

  asDescription [ "???" ]
]
4

2 回答 2

5

在 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。特别是,它无需任何修改即可使用

  1. 文件(的实例FileStream
  2. 套接字(的实例SocketStream
  3. Transcript

换句话说,通过实现免费#printOn:获取#asString(继承)和——同时——将对象的表示转储到文件和套接字上的能力。这Transcript特别有趣,因为它支持Stream写入协议,因此可以在向外部设备发送任何字节之前用于测试目的。

记住!

在 Smalltalk 中,目标是同时拥有行为简单且通用的对象,而不仅仅是简单!

于 2019-03-24T12:43:37.347 回答
2

正如 lurker 在评论中所写,在 asDescription 中发送 asString 消息。

asDescription
    ^ self asString

通常这样做是为了从一个类中公开额外的接口/协议,以实现兼容性或作为内置适配器。如果您创建的新东西不必适合其他任何地方,请考虑为每个操作只使用一个名称。

编辑:如果您真的在重新导出语义之后并且不希望在上面的委托中涉及额外的消息发送,那么可能有一种方法可以将 asString 的 CompiledMethod 第二次放在类的方法字典中姓名。但我也不确定这会起作用,我也不知道 GNU Smalltalk 中的协议如何操作方法字典。看看Behavior类的文档。另外,我不会认为这是对 Smalltalk 进行编程,而是在修补系统。

于 2019-03-24T10:37:30.483 回答