|
| 1 | +## Beacons and Satellites @ch:beaconIn this chapter you will build a simulator for beacons and satellites. Beacons are in the sea and collect data and from time to time they should synchronise with satelittes to send data. In reality, satelittes broadcast signals and beacons are polling at regular interval for signals, then once they know that they are in range based on the first signal, a communication is established and data is exchanged.In the simulator we will present how we can implement communication between losely coupled objects. You will build step by step different variations around the observer/observable idiom. This idiom is important since it is used in Model-View-Controller and Self addressed stamped enveloppe \(S.A.S.E\) patterns. Beacons will register to satellites and when the satelittes are in range they will notify the beacons interested in the notification. ### DescriptionA beacon is inside the sea and it collects data. It is fully autonomous. After a certain period of time it migrates to the surface waiting to send the data it collected.To communicate with satelittes, a satelitte should be available, i.e., within the zone where the beacon is.A satellite is moving around earth at a certain speed and ranging a portion of sea. It can only communicate with beacons within such range.The system is fully dynamic in the sense that new beacons may be added or removed.Satelittes may be present or not.### A simple model```Object subclass: #Satelitte |
| 2 | + instanceVariableNames: 'observers' |
| 3 | + classVariableNames: '' |
| 4 | + package: 'SatelitteAndBeacon'``````Satelitte >> initialize |
| 5 | + observers := OrderedCollection new``````Object subclass: #Beacon |
| 6 | + instanceVariableNames: 'data' |
| 7 | + classVariableNames: '' |
| 8 | + package: 'SatelitteAndBeacon'```### V1: Simple observer / observableWe start with a simple schema where beacons - register to satellites and- when the satelittes are in range they notify the beacons that registered.#### RegistrationA beacon register to a satellite as follows:```Satelitte >> register: aBeacon |
| 9 | + self addObserver: aBeacon```#### Notification```Satelitte >> position: aPoint |
| 10 | + position := aPoint. |
| 11 | + self notify``````Satelitte >> notify |
| 12 | + observers do: [ :aBeacon | aBeacon salelittePositionChanged: self ]```### V1 Implementation???### V2: AnalysisThis first implementation has several drawbacks.- One of the problem is that the message is hardcoded. - Second Imagine that the satellite should emit different notification for its position, protocol to be used, frequency.... and each kind of beacon can register for the notification kinds that fits it. We must have a list of each kind of observed property.### V2: Introducing events```Satelitte >> register: aBeacon forEvent: aEventClass |
| 13 | + aSatelitte1 addObserver: aBeacon1 with: aEventClass``````Satelitte >> addObserver: anObserver with: anEventClass |
| 14 | + observerDict at: anEventClass iAbsentPut: [OrderedCollection new]. |
| 15 | + (observerDict at: anEventClass) add: anObserver``````Satelitte >> position: aPoint |
| 16 | + position := aPoint. |
| 17 | + self notify: (PositionChanged with: self)``````Satelitte >> notify: anEvent |
| 18 | + (observersDict at: anEvent class) ifPresent: [ :aBeaconList | |
| 19 | + aBeaconList do: [:aBeacon| anEvent fireOn: aBeacon ]```#### Implementation```Object subclass: #SBEvent |
| 20 | + instanceVariableNames: 'observable' |
| 21 | + classVariableNames: '' |
| 22 | + package: 'SatelitteAndBeacon'``````SBEvent subclass: #SBPositionChanged |
| 23 | + instanceVariableNames: '' |
| 24 | + classVariableNames: '' |
| 25 | + package: 'SatelitteAndBeacon'``````SBEvent subclass: #SBProtocolChanged |
| 26 | + instanceVariableNames: '' |
| 27 | + classVariableNames: '' |
| 28 | + package: 'SatelitteAndBeacon'``````SBPositionChanged >> fireOn: anObserver |
| 29 | + anObserver salelittePositionChanged: observable``````SBProtocolChanged >> fireOn: anObserver |
| 30 | + anObserver salelitteProtocolChanged: observable```#### V2 analysisAdvantages- we reuse the same mechanism for different kind of observable properties.Drawbacks- One event means that the message is also hardcoded. There is tight dependencies between the event type and the kind of behavior that is available on the observer side. ### V3 Specifying the messageNow the observer can specify the message that it wants to receive. ```aSatelitte1 when: SBPositionChanged send: #readyForHandShakeWith: to: aBeacon1``````aSatelitte1 when: SBProtocolChanged send: #useProtocol: to: aBeacon1``````Satelitte >> when: anEventClass send: aSelector to: anObserver |
| 31 | + observerDict at: anEventClass iAbsentPut: [OrderedCollection new]. |
| 32 | + (observerDict at: anEventClass) add: (aSelector -> anObserver)``````Satelitte >> position: aPoint |
| 33 | + position := aPoint. |
| 34 | + self notify: (PositionChanged with: self)``````Satelitte >> notify: anEvent |
| 35 | + (observersDict at: anEvent class) ifPresent: [ :aBeaconList | |
| 36 | + aBeaconList do: [ :aBeaconAssoc | |
| 37 | + aBeaconAssoc value perform: aBeaconAssoc key with: anEvent) ]```### V5 Factoring out the announcerThe notification and management at notification should be packaged as a separate class so that we can reuse it by just delegating to it. ```Object subclass: #BSAnnouncement |
| 38 | + instanceVariableNames: 'selector observer'``````Object subclass: #BSAnnouncer |
| 39 | + instanceVariableNames: 'observerDict'``````BSAnnouncer >> when: anEventClass send: aSelector to: anObserver |
| 40 | + observerDict at: anEventClass iAbsentPut: [ OrderedCollection new] . |
| 41 | + (observerDict at: anEventClass) add: |
| 42 | + (BSAnnouncement send: aSelector to: anObserver)``````BSAnnouncer >> notify: anEvent |
| 43 | + (observersDict at: anEvent class) ifPresent: [ :aBeaconList | |
| 44 | + aBeaconList do: [ :anAnnouncement | |
| 45 | + anAnnouncement observer |
| 46 | + perform: anAnnouncement selector |
| 47 | + with: anEvent) ]``````Satelitte >> notify: anEvent |
| 48 | + self announcer notify: anEvent``````Satelitte >> when: anEventClass send: aSelector to: anObserver |
| 49 | + self announcer when: anEventClass send: aSelector to: anObserver```### Discussion about lookup of events |
|
0 commit comments