Issott_Common Design Patterns for Symbian OS-The Foundations of Smartphone Software_0470516356 (779879), страница 21
Текст из файла (страница 21)
Here we show it being doneduring the destruction of the event consumer but it could be done earlier.CEventConsumer::∼CEventConsumer(){iEventGenerator.DeregisterEventConsumerL(*this);}The implementation of the event mixin functions depend on how thispattern is being used in your specific solution:void CEventConsumer::MemEventHasOccurredL(){// Do some processing in response to the event}ConsequencesPositives• This pattern reduces the power usage of your components.• This pattern is simple to implement and provides considerable flexibility:• Event generators know when there are event consumers listeningfor event signals.100EVENT-DRIVEN PROGRAMMING• Event generators can send event signals by calling a mixin classfunction at any point while an event consumer remains registered.• Event signals can be warm or hot, as appropriate.• Event generators and event consumers are de-coupled.
In particular this allows for new event consumers8 to be registered easilywhich makes your software more adaptable for future changes aswell as making testing easier by enabling patterns such as MockObjects.9Negatives• Components are limited to sending event signals between objectswithin a single thread.• The pattern doesn’t provide any way for security checks to be performed on either the event generators or the event consumers.• Event generators can be broken by badly behaved event consumerstaking a long time to respond to the synchronous event signal.• When used to define an exported Event Mixin API used across a DLLboundary, it cannot be extended without risking binary compatibilitybreaks for the event consumers that inherit from the event mixinclass.10• Event generators need to be aware that event consumers may makesome callback into the event generator object whilst it is handlingthe event signal, i.e.
within MemEventHasOccurredL(). This cancause problems because the event generator could be in some unstableintermediate state or (potentially more disastrous!) could simply deletethe event generator object entirely.Example ResolvedAs mentioned in the problem example, a way is required to send eventsignals between the generic OBEX protocol implementation, as the eventgenerator, and the service-specific logic, or OBEX server application, asthe event consumer.
This is solved by creating an event mixin class,MObexServerNotify, to interface between them.This event mixin class, defined in epoc32\include\obexserver.h, contains several member functions which act as event8Event generators could also be changed easily if a management class was responsiblefor joining event consumers to event generators.9 en.wikipedia.org/wiki/Mock object .10 This is due to the way in which vtables are used to enable polymorphism.
Adding,removing or reordering virtual functions in a class risks two executables ’disagreeing‘ aboutthe number or order of virtual functions in a class, which can lead to hard-to-find binarycompatibility breaks.EVENT MIXIN101signals for the different events that can happen during an OBEX sessionwith a select few shown below:class MObexServerNotify{public:virtual TInt ObexConnectIndication(const TObexConnectInfo& aRemoteInfo,const TDesC8& aInfo) = 0;virtual CObexBufObject* PutRequestIndication() = 0;...};You’ll note from the absence of trailing Ls that Escalate Errors (seepage 32) is not being used to escalate errors from these functions, whichshows that alternative error-handling strategies can be used with thispattern. In this case, function return codes are used.The ObexConnectIndication() function is called when a newOBEX session has been established.
A TObexConnectInfo object ispassed into the function, which holds contextual information aboutthe newly connected OBEX client. An OBEX server application inheriting MObexServerNotify could therefore implement this function toprepare itself for receiving OBEX requests.One such request is the Put request to transfer an object from the OBEXclient to the OBEX server. When the generic OBEX server code receivessuch a request, it signals this event to the event consumer by calling thePutRequestIndication() function. The OBEX server application isexpected to return a pointer from the function to the event generator,either of NULL (to indicate that the OBEX server application is unwillingto accept the Put request) or to a CObexBufObject which the genericOBEX protocol implementation can use as a receptacle for the object thatthe OBEX client is sending.The generic OBEX server protocol implementation, as represented bythe CObexServer class, has a registration function by which the OBEXserver application can provide an MObexServerNotify*.
BecauseCObexServer can’t perform any meaningful OBEX processing without an implementation of MObexServerNotify, the semantics of thefunction are to ’start‘ the CObexServer:11TInt Start(MObexServerNotify* aOwner);In practice, the MObexServerNotify class offers an example ofhow restrictive the event mixin pattern is when used as an API usedacross a DLL that needs to remain compatible.
The set of functionswithin MObexServerNotify cannot be added to without breakingcompatibility. In brief, to do so would risk a mismatch between the vtable11 Thiscan also be found in epoc32\include\obexserver.h.102EVENT-DRIVEN PROGRAMMINGentries expected by the DLL that contains the CObexServer class andthe actual vtable entries present for an MObexServerNotify-derivedclass contained in some OBEX server application executable compiledagainst an earlier version of MObexServerNotify.Other Known UsesUses of event mixin classes are numerous in Symbian OS.
Some examplesinclude:• Messaging EngineThe MMsvSessionObserver class defined in epoc32\include\msvapi.h is used by clients of the messaging server to register fornotification of messaging-related events. The client of the messagingserver, as an event consumer, inherits from this event mixin class andimplements the pure virtual function it provides.Event consumers can then register for messaging-related eventsignals by using the CMsvSession::OpenSyncL() or CMsvSession::OpenAsyncL() functions.
Having done this, it receivesevent signals when interesting messaging-related events occur, suchas when a new message entry appears in the message index.• EikonThe MEikScrollBarObserver class is inherited by event consumers interested in events related to user interaction with a particularinstance of the CEikScrollBar class.Variants and Extensions• Registering Multiple Event Consumers with a Single Event GeneratorHere an event generator is not limited to supporting a single eventconsumer.
The event generator may store zero, one or multiple eventconsumers via event mixin pointers. When dealing with multipleevent consumers, it becomes important to ensure that the eventconsumer de-registration function provided by the event generatortakes a reference or pointer to the event consumer to be de-registered,to distinguish it from the other registered event consumers. This variantof the pattern is most similar to Observer [Gamma et al., 1994].• Asynchronous Event MixinsThis pattern is often coupled with Active Objects (see page 133) tosupport asynchronous delivery of event signals.
The event generatorowns an active object, such as CAsyncCallback, which it informs ofevent signals. This active object completes its own TRequestStatusobject so that its RunL() is executed at the next opportunity to actuallysend the event signal by synchronously calling the appropriate eventEVENT MIXIN103mixin function on the event consumer. Using Active Objects (seepage 133) helps protect the event generator from badly behavedevent consumers by further decoupling them.References• Observer [Gamma et al., 1994] is a similar pattern described for adifferent context.• Escalate Errors (see page 32) describes how to handle error conditionswhen processing events.• Active Objects (see page 133) is used in conjunction with this patternif you need an asynchronous event mixin.• Publish and Subscribe (see page 114) is an alternative event-drivenprogramming style that allows event generators to broadcast eventsignals across thread and process boundaries.