[Announcements] Adding scope to announcements

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[Announcements] Adding scope to announcements

Wouter Gazendam
Hi,

When working with announcements I find it strange I can only specify
subscriptions to announcements on the subject level. What I like to do
is be able to add a subscription to a certain aspect of a model:

        employee := Employee new.
        (employee scopeForAspect: #name) when: ValueChanged do: [nameChanged := true].
        employee when: ValueChanged do: [employeeChanged := true].
        employee name: 'Piet'.
        self assert: nameChanged = true
        self assert: employeeChanged = true

With:

Employee>>name: anObject
        (self scopeForAspect: #name) announce: ValueChanged

So the [triggered := true] block would only be triggered when the name
aspect changes. But the [employeeChanged := true] block gets also
triggered by virtue of being subscribed to a larger scope.

A nice addition would be to subscribe to a collection of objects

When using a sort of ObservableModel this kind of usage doesn't really
occur since an ObservableModel usually has only one aspect (the
#value) to consider.
Do you guys have the idea I'm designing my application in a weird way,
can it be done in the current announcements framework? What I don't
like to have is to receive annoucements for all sorts of aspects and
then filter them out. I don't want the announcements I'm not
interested in not to arrive at my subscriber.

Any ideas would be appreciated,

Wouter

Reply | Threaded
Open this post in threaded view
|

Re: [Announcements] Adding scope to announcements

Ladislav Lenart
Wouter Gazendam wrote:

> Hi,
>
> When working with announcements I find it strange I can only specify
> subscriptions to announcements on the subject level. What I like to do
> is be able to add a subscription to a certain aspect of a model:
>
>     employee := Employee new.
>     (employee scopeForAspect: #name) when: ValueChanged do: [nameChanged
> := true].
>     employee when: ValueChanged do: [employeeChanged := true].
>     employee name: 'Piet'.
>     self assert: nameChanged = true
>     self assert: employeeChanged = true
>
> With:
>
> Employee>>name: anObject
>     (self scopeForAspect: #name) announce: ValueChanged
> So the [triggered := true] block would only be triggered when the name
> aspect changes. But the [employeeChanged := true] block gets also
> triggered by virtue of being subscribed to a larger scope.

Hi,

I would do the following:


[1] Define the #name: method

        Employee>>name: aString
                name := aString.
                self announce: EmployeeNameChanged.
                self announce: EmployeeChanged.

Alternateively, you could define EmployeeNameChanged as a subclass of
EmployeeChanged. In that case the method would look like this:

        Employee>>name: aString
                name := aString.
                self announce: EmployeeNameChanged.

But keep in mind that the order in which you receive the announcements
is not given in this case.


[2] Subscribing

I would replace

        employee scopeForAspect: #name

with

        employee when: EmployeeNameChanged do: [nameChanged := true].


[3] Example

Then, the example above would look like this:

        nameChanged := false.
        employeeChanged := false.
        employee := Employee new.
        employee when: EmployeeNameChanged do: [nameChanged := true].
        employee when: EmployeeChanged do: [employeeChanged := true].
        employee name: 'Piet'.
        self assert: nameChanged = true
        self assert: employeeChanged = true

This is the scheme I use in daily life with announcements and it quite
well suites my needs.

Hope this helps,

Ladislav Lenart


Reply | Threaded
Open this post in threaded view
|

Re: [Announcements] Adding scope to announcements

Ladislav Lenart
Wouter Gazendam wrote:
> This would mean I'd have to make a Announcement class for each
> DomainClass - aspect combination. This would run into thousands in my
> system.

Well,

if you could live without anouncement inheritance, you could have
NameChanged announcement instead of EmployeeNameChanged and you
could use this announcement for all objects with name aspect. In this
case, you would have to do more manual work (see the first Employee>>name:).
But on the other hand, you would have specific announcement class
for each aspect you're interested in, no matter what the total
number of domain classes is.

I think, having thousands of Announcement classes in this case is not
a problem anymore, because announcements are object replacement for
triggerEvent model; basically each triggered symbol means specific
announcement class...

Ladislav Lenart

>>         Employee>>name: aString
>>                 name := aString.
>>                 self announce: EmployeeNameChanged.
>>                 self announce: EmployeeChanged.
>>
>> Alternateively, you could define EmployeeNameChanged as a subclass of
>> EmployeeChanged. In that case the method would look like this:
>>
>>         Employee>>name: aString
>>                 name := aString.
>>                 self announce: EmployeeNameChanged.
>>
>> But keep in mind that the order in which you receive the announcements
>> is not given in this case.

Reply | Threaded
Open this post in threaded view
|

Re: [Announcements] Adding scope to announcements

Vassili Bykov
In reply to this post by Wouter Gazendam
Wouter Gazendam wrote:

>
>     employee := Employee new.
>     (employee scopeForAspect: #name) when: ValueChanged do: [nameChanged
> := true].
>     employee when: ValueChanged do: [employeeChanged := true].
>     employee name: 'Piet'.
>     self assert: nameChanged = true
>     self assert: employeeChanged = true
>
> With:
>
> Employee>>name: anObject
>     (self scopeForAspect: #name) announce: ValueChanged
>
 > [...]
>
> Any ideas would be appreciated,

You've already outlined a very simple solution, missing implementation
details. :)

Instead of using Employee itself as the announcer, create a dedicated
HierarchicalAnnouncer with a 'parent' link. Implement
HierarchicalAnnouncer>>announce: as

        super announce: anAnnouncement.
        parent announce: anAnnouncement.

In #initialize of Employee, create one such announcer for each
individual aspect, with the parent link pointing to the receiver
Employee. Remember those announcers in something like a Dictionary and
implement #announcerFor: method to retrieve them. (You could call the
method #scopeForAspect: too, I just find #announcerFor: less of
cognitive load).

Then everything should work exactly as your test code assumes.

--
Vassili Bykov <[hidden email]>

[:s | s, s printString] value: '[s: | s, s printString] value: '