子类化流

时间:2015-03-28 18:04:02

标签: smalltalk pharo gemstone

我有兴趣创建自己的Stream子类,我想知道我应该覆盖哪些方法(在pharo和Gemstone上部署)。我有一个包含各种类型的东西的集合,我希望能够流式传输它的一个子集,包含一个类的元素。我不想复制集合或使用collect:block,因为集合可能很大。我的第一个用例是这样的:

stream := self mailBox streamOf: QTurnMessage.
stream size > 1
    ifTrue: [ ^ stream at: 2 ]
    ifFalse: [ ^ nil ]

有关要覆盖哪些方法的指示?

2 个答案:

答案 0 :(得分:5)

在Smalltalk中,当我们说Stream时,我们引用响应基本协议的对象,这些对象由一些方法给出,例如#next,#nextPut:,#content等。所以,在进一步详细说明之前我会说stream at: 2,正如你在你的例子中所说,不是一个非常恰当的表达。 Stream的更合适的表达式是

stream position: 2.
^stream next

因此,您必须考虑的第一件事是您是在寻找Stream还是Collection。这个基本决定取决于您的对象必须实现的行为。

使用Stream的子类,以防您决定使用#next枚举元素,即大部分按顺序排列。但是,如果您想通过at: index访问您的元素,请使用SequenceableCollection.的子类

为对象建模

如果您选择流,则必须决定是仅访问它们进行阅读操作还是还要修改其内容。您对问题的描述似乎表明您将只阅读它们。因此,首先要实现的基本协议是

#next "retrieve the object at the following position and advance the position"
#atEnd "answer with true if there are no more objects left"
#position "answer the current position of the implicit index"
#position: "change the implicit index to a new value"

此外,如果您的信息流只读,请将您的班级设为ReadStream的子类。

如果要继承更高级的方法,还需要实现一些其他额外的消息。一个例子是#next:,它会检索几个连续元素的子集合(其大小由参数给出。)

如果您认为将对象建模为集合会更好,那么您必须实现的基本协议包含以下三种方法

#at: index "retrieve the element at the given index"
#size "retrieve the total number of elements"
#do: aBlock "evaluate aBlock for every element of the receiver"

(我认为您的馆藏不得支持at:put:.

最近我们遇到了你正在描述的同样的问题,并决定将我们的对象建模为集合(而不是流。)但是,不管你最终会遵循哪种方法,我认为你应该尝试两者并看看哪一个更好。没有人会比你的Smalltalk系统给你更好的建议。

顺便说一句,请注意,如果您有{可序列的} Collection,您将免费获得Stream:只需将#readStream发送到您的收藏中!

答案 1 :(得分:2)

我需要覆盖nextatEnd。我的Stream子类接受一个块和一个集合,并迭代block求值为true的集合的所有元素。

使用示例:

e := Array with: 1 with: 2 with: 3. 
a := QStream collection: e block: [ :i| i odd ].

a next. "1"
a next. "3"

以下是它的核心:

Stream subclass: #QStream
    instanceVariableNames: 'collection block index found'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'QDialog-Core'

initialize
    super initialize.
    index := 1.
    self search.

next
    | result |
    result := found.
    self search.
    ^result.

search
    [ index < collection size and: [ (block value: (collection at: index)) not ] ]
      whileTrue: [ index := index + 1 ].
    self atEnd
        ifTrue: [ ^ found := nil ]
        ifFalse: [ 
            found := collection at: index.
            index := index + 1 ]

atEnd
^   index > collection size