Подклассы Stream

Я заинтересован в создании своего собственного подкласса Stream, и мне интересно, какие методы мне следует переопределить (развертывание на pharo и Gemstone). У меня есть коллекция с различными типами вещей, и я хочу иметь возможность передавать ее по подмножеству, содержащему элементы класса. Я не хочу копировать коллекцию или использовать коллекцию: блок, потому что коллекция может быть большой. Мой первый вариант использования выглядит примерно так:

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

Любые указатели на какие методы переопределить?

2 ответа

В Smalltalk, когда мы говорим Stream мы ссылаемся на объекты, которые отвечают базовому протоколу, заданному несколькими методами, такими как #next, #nextPut:, #contents и т. д. Итак, прежде чем углубляться в детали, я бы сказал, что 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 в вашу коллекцию!

Мне нужно переопределить next а также atEnd, мой Stream подкласс принимает блок и коллекцию, и перебирает все элементы коллекции, для которых block оценивает как истинное.

Пример использования:

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
Другие вопросы по тегам