Here is an interesting question that often comes up when writing components, and one which we faced when embedding our components: “How do the components communicate with each other in a way that doesn’t bind them together explicitly?” That is, how does a child component send a message to its parent component without explicitly knowing who the parent is? Designing a component to refer to its parent (as we did) is not always an ideal solution, since the interfaces of different parents may be different, and this would prevent the component from being reused in different contexts.
Another approach is to adopt a solution based on explicit dependencies, also called the change/update mechanism. Since the early days of Smalltalk, it has provided a built-in dependency mechanism based on a change/update protocol—this mechanism is the foundation of the MVC framework itself. A component registers its interest in some event and that event triggers a notification.
Announcements. Perhaps the most flexible and powerful approach is to use a more recent framework called Announcement. While the original dependency framework relied on symbols for the event registration and notification, Announcement promotes an object-oriented solution; i.e. events are standard objects. Originally developed by Vassili Bykov, this framework has been ported to several Smalltalk implementations, and is popular with Seaside developers.
The main idea behind the framework is to set up common announcers and to let clients register to send or receive notifications of events. An event is an object representing an occurrence of a specific event. It is the place to define all the information related to the event occurrence. An announcer is responsible for registering interested clients and announcing events. In the context of Seaside, we can define an announcer in a session. For more information on sessions see Chapter 18.
An Example. Here is an example taken from Ramon Leon’s very good Smalltalk blog (at http://onsmalltalk.com/). This example shows how we can use announcements to manage the communication between a parent component and its children as for example in the context of a menu and its menu items.
First we add a reference to a new
Announcer to our session:
^ announcer ifNil: [ announcer := Announcer new ]
Announcement subclass: #RemoveChild
Each subclass can have additional instance variables and accessors added to hold any extra information about the specific announcement such as a context, the objects involved etc. This is why announcement objects are both more powerful and simpler than using symbols.
RemoveChild class>>child: aChild
^ self new
child := anChild
Any component interested in this announcement registers its interest by sending the announcer the message
on: anAnnouncementClass do: aBlock or
on: anAnnouncementClass send: aSelector to: anObject. You can also ask an announcer to
unsubcribe: an object.
on:send:to: are strictly equivalent to the messages
subscribe: anAnnouncementClass do: aValuable (an object understanding
subscribe: anAnnouncementClass send: aSelector to: anObject.
self session announcer on: RemoveChild do: [:it | self removeChild: it child]
self children remove: aChild
And any component that wants to fire this event simply announces it by sending in an instance of that custom announcement object:
self session announcer announce: (RemoveChild child: self)
Note that depending on where you place the announcer, you can even have different sessions sending events to each other, or different applications.
Pros and cons. Announcements are not always the best way to establish communication between components and you have to decide the exact design you want. On one hand, announcements let you create loosely coupled components and thus maximize reusability. On the other hand, they introduce additional complexity when you may be able solve your communication problem with a simple message send.