Пересылка сообщений в Smalltalk - PullRequest
4 голосов
/ 19 мая 2009

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

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].

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

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

EDIT : я должен добавить, что делегаты того же класса, что и объект, поэтому я не могу просто переопределить DoesNotUnderstand:.

Ответы [ 5 ]

7 голосов
/ 20 мая 2009

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

someObject sendMessage: aSelector withArguments: argumentsList

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

sendMessage: aSelector withArguments: argumentsList

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

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

| аргументы |

аргументы: = массив с: Объект новый с: 1234,5 с помощью: ('ключ' -> 'значение').

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

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

2 голосов
/ 20 мая 2009

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

2 голосов
/ 19 мая 2009

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

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
1 голос
/ 20 мая 2009

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

MyobjectClass>>SendMessage: aMessage

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

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

update: 
update:with:
update:with:from:
0 голосов
/ 19 мая 2009

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

MyObjectClass>>someMethod
subobjects do: [:each | each someMethod]
...