Smalltalk:定制施工的正确方法

时间:2017-04-28 06:07:34

标签: initialization smalltalk pharo metaclass

哪本书最能描述制作自定义构造函数的正确方法?

例如,我想要特殊的文件系统(在RDBMS存储中模拟)。

Object subclass: #C1_Object
C1_Object subclass: #C1_File
    instanceVariableNames: 'stream name'

用例:

  1. C1_File new: 'blablabla'
    1. C1_File create: 'blablabla'
    2. (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
      

3 个答案:

答案 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: aCollectionText 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"