Пересылка сообщений в Smalltalk

Поэтому я пишу приложение, в котором у одного объекта есть группа объектов-делегатов, которым он пересылает сообщения. Идея в том, что я могу сказать

someObject sendMessage:aMessage

и aMessage будет отправлено всем делегатам someObject (для любого значения aMessage). Единственный способ, которым я смог сделать это, это что-то вроде:

sendMessage:aMessage

| sel chunks kwords arglist msg |
chunks := aMessage findTokens:' '.
kwords := Array new:(chunks size).
arglist := Array new:(chunks size).
1 to: (chunks size) do: [:i | 
    kwords at:i put:((chunks at:i) findTokens:':') at:1.
    arglist at:i put:((chunks at:i) findTokens:':') at:2].
sel := ''.
kwords do:[:word | sel := sel,word,':'].

msg := Message selector:sel arguments:arglist.
delegates do:[:del | del perform:msg selector with:msg arguments].

Это работает, но должен быть лучший способ. Это решение ограничивает аргументы быть строками и выглядит просто ужасно. Кто-нибудь знает более чистый, лучший способ пересылки сообщений?

Кстати, я использую писк, но решение, независимое от реализации, было бы предпочтительным;)

РЕДАКТИРОВАТЬ: я должен добавить, что делегаты того же класса, что и объект, поэтому я не могу просто переопределить DoesNotUnderstand:.

5 ответов

Решение

Поскольку вы хотите передавать объекты в качестве аргументов, вам придется передавать их в виде отдельного списка с использованием шаблона сообщения, подобного следующему:

someObject sendMessage: aSelector withArguments: argumentsList

Тогда вы бы реализовали #sendMessage: withArguments: as:

sendMessage: aSelector withArguments: argumentsList

делегаты делают:[:del | del execute: aSelector withArguments::argumentsList].

и вы сможете пересылать произвольно сложные сообщения, используя реальные объекты в качестве аргументов:

| аргументы |

arguments: = Array with: Object new with: 1234.5 with: ('key' -> 'value').

someObject sendMessage: #foo: bar: baz: withArguments: arguments

Я думаю, что это переносимо для большинства диалектов...

В Squeak смотрите класс ObjectTracer. Вы можете использовать его для перехвата всех сообщений, отправляемых Объекту.

Попробуйте реализовать это (он будет только пересылать сообщения, которые не поняты объектом, имеющим делегатов):

doesNotUnderstand: aMessage 
    delegates
        do: [:delegate | aMessage sendTo: delegate]

Вы можете создать объекты Message явно как:

msg := Message selector: #foo arguments: #(bar baz)
"then use them like:"
anObject perform: msg selector with: msg arguments

Ну, не зная, что такое aMessage, и поскольку вы упомянули все ваши объекты делегатов одного класса, я бы сделал что-то вроде:

MyobjectClass>>SendMessage: aMessage

   self doSomethingUsefulOnThisInstanceIfApplicable: aMessage.
   self dependents do: [:ea | ea SendMessage: aMessage ] .

Вы также можете посмотреть, может ли работать с вами любое из следующих сообщений: (это от Cincom VisualWORKS)

update: 
update:with:
update:with:from:

Почему бы просто не использовать полиморфизм, то есть реализовать этот метод в классе каждого объекта, который вы вызываете? Затем вы реализуете в своем объекте метод с тем же именем, который просто делегирует вызов всем подобъектам. Что-то вроде:

MyObjectClass>>someMethod
subobjects do: [:each | each someMethod]
Другие вопросы по тегам