Issott_Common Design Patterns for Symbian OS-The Foundations of Smartphone Software_0470516356 (779879), страница 69
Текст из файла (страница 69)
Theserver owns the singleton and sends copies on request to its clients.• Publish and Subscribe kernel serviceYou may find that if all you wish to do is provide a system-widesingleton then using the Publish and Subscribe kernel service is easierto implement. Note that whilst this is the same technology as usedin Publish and Subscribe (see page 114), the way it is used differs.For instance, whilst the owning process does indeed ‘publish’ thesingleton, the client-side DLL does not ‘subscribe’ for notificationof changes. Instead, it simply calls RProperty::Get() when aninstance of the singleton is needed.• Message QueuesMentioned for completeness here as they could be used but the otheralternatives are either more familiar or simpler to use.The disadvantage of having a system-wide singleton is the impacton run-time performance.
The main overhead arises from the contextswitch involved in the IPC message to and from the process owning thesingleton and, if the singleton contains a lot of data, the copying of the singleton.SINGLETON367Positive Consequences• Allows access by multiple processes and thus provides a single,system-wide, instance.• The Symbian OS IPC mechanisms manage the multiple requests foraccess to a single shared resource and handle most of the problemsof making the singleton thread-safe.• Calling code can be unaware of whether it is accessing a singleton – the client-side implementation is simple to use, while the processsupplying the singleton can be customized as necessary.Negative Consequences• Additional execution time caused by the IPC and copying of thesingleton data although any implementation of Singleton thatsupports access from multiple processes will also be affectedby this.• The implementation of the singleton is necessarily more complex,requiring creation of a client-side DLL and use of an IPC mechanism.The implementation can be heavyweight if only a few properties oroperations are offered by the singleton.Solution SummaryFigure 9.7 summarizes the decision tree for selecting a singleton implementation on Symbian OS.Example ResolvedThe control environment (CONE) implements class CCoeEnv as a singleton class.
Implementation B is used and a pointer to the singleton is storedin TLS. Internally, CCoeEnv accesses the singleton instance through a setof inline functions, as follows:// coetls.hclass CCoeEnv;inline CCoeEnv* TheCoe() { return((CCoeEnv*)Dll::Tls()); }inline TInt SetTheCoe(CCoeEnv* aCoe) { return (Dll::SetTls(aCoe)); }inline void FreeTheCoe() { Dll::FreeTls(); }The constructor of CCoeEnv uses an assertion statement to confirmthat the TLS slot returned by TheCoe() is uninitialized.
It then sets theTLS word to point to itself, by calling SetTheCoe(this).When an object of any class, instantiated within a thread that has acontrol environment (i.e. the main thread of an application) needs access368MAPPING WELL-KNOWN PATTERNS ONTO SYMBIAN OSFigure 9.7 Symbian OS Singleton implementation decision treeto the CCoeEnv singleton, it may simply include the coemain.h headerand call CCoeEnv::Static() which is implemented as follows incoemain.cpp:EXPORT_C CCoeEnv* CCoeEnv::Static(){return(TheCoe());}It can then be used by applications as follows:CCoeEnv::Static()->CreateResourceReaderLC(aReader, aResourceId);Alternatively, CCoeControl::ControlEnv() can be used by applications to retrieve the singleton instance.
However, this method returnsa cached pointer to the CCoeEnv singleton, which the CCoeControlclass stores in its constructor (by making a call to TheCoe()).SINGLETON369The use of a cached pointer is more efficient than calling CCoeEnv::Static() because it avoids making an executive call to Dll::Tls() toaccess the singleton. Within the application framework, using a cachedpointer is acceptable, because the lifetime of the CCoeEnv singletonis controlled and, if the application is running, the CCoeEnv objectis guaranteed to exist (and to be at the same location as when theCCoeControl constructor first cached it).In general, it is not considered a good thing to cache pointers tosingleton objects for future access, because it makes the design inflexible.For example, the singleton can never be deleted without providing somekind of mechanism to ensure that those using a cached pointer don’taccess dead memory.
The Instance() method should generally beused to access the singleton, because that allows more flexibility to theprovider of the singleton. For example, it could save on memory bydeleting the object if available memory drops below a certain thresholdor if it has not been accessed recently or regularly.The implementations given in the Solution section anticipate that someclients may mistakenly cache a pointer to the singleton ‘because theycan’ and instead return a reference from Instance(), which is moredifficult to code around (although it is still possible).Other Known UsesThis pattern is widely used across Symbian OS since virtually everyapplication makes use of the CCoeEnv singleton in its thread whilst everyserver is itself a singleton for the whole system.Variants and Extensions• Destroying the SingletonAll the implementations discussed have specified the destructor forthe singleton class as private.
This is because, if the destructor waspublic, it is possible that the singleton instance could be deleted,leaving the singleton class to hand out ‘dangling references’ to thedeleted instance. Unless the design is such that this can be guaranteednot to occur, it is preferable to prevent it.Since the singleton class has responsibility for creation of theinstance, it must generally have responsibility of ownership and,ultimately, cleanup.One option could be to allow the singleton destruction to beimplicit. C++ deletes static objects automatically at program termination and the language guarantees that an object’s destructor will becalled and space reclaimed at that time. It doesn’t guarantee the calling order, but if there is only one singleton in the system, or the orderof destruction is unimportant, this is an option when Implementations370MAPPING WELL-KNOWN PATTERNS ONTO SYMBIAN OSA or C (using WSD) are chosen. Please see [Vlissides, 1996] for moreinformation about this approach, which requires the use of a friendclass to destroy the singleton.Another option is to use the atexit function provided by thestandard C library, to register a cleanup function to be called explicitlywhen the process terminates.
The cleanup function can be a memberof the singleton class and simply delete the singleton instance. Pleasesee [Alexandrescu, 2001] for further details.However, you may want to destroy the singleton before the processterminates (for example, to free up memory if the object is no longerneeded).
In this case, you have to consider a mechanism such as reference counting to avoid dangling references arising from prematuredeletion. For example, to extend Implementation A, with the additionof a static Close() method:class CSingleton : public CBase{public:// To create the singleton instancestatic void CreateL();// To access the singleton instancestatic CSingleton& Instance();static void Close();private: // The implementations of the following are omitted forclarityCSingleton* NewL();CSingleton();∼CSingleton();void ConstructL();private:static CSingleton* iSingletonInstance;TInt iRefCount;};/*static*/ void CSingleton::CreateL(){++(iSingletonInstance->iRefCount);if (!iSingletonInstance){ // Create the singleton if it doesn’t already existiSingletonInstance = CSingleton::NewL();}}/*static*/ CSingleton& CSingleton::Instance(){ASSERT(iSingletonInstance);return (*iSingletonInstance);}SINGLETON371// Must be called once for each call to CreateL()/*static*/ void CSingleton::Close(){if (--(iSingletonInstance->iRefCount)<=0){delete iSingletonInstance;iSingletonInstance = NULL;}}References• Lazy Allocation (see page 63) can be used when allocating theSingleton instance.• Client–Server (see page 182) may be used for Implementation E.• [Saumont, 2007], [Rainsberger, 2001] and [Densmore, 2004] discussthe problems of using this pattern.• In Monostate, as described in [Ball and Crawford, 1997], there maybe more than one object of a class but all share the same state.372MAPPING WELL-KNOWN PATTERNS ONTO SYMBIAN OSAdapterIntentTransform calls on one interface into calls on another, incompatible,interface without changing existing components.AKAEmulator [Buschmann et al., 1996]ProblemContextThere is a pre-existing component, the adaptee, which exposes an interface that you wish to use via an alternative incompatible interface, thetarget.SummaryYou need to resolve one or more of the following:• You wish to reduce your development costs by porting a pre-existingcomponent, the adaptee, to a new environment.• You have re-engineered a component, the adaptee, but you wishto support the old interface, the target, to preserve compatibility forlegacy clients.• You wish to increase the functionality and flexibility of a componentby re-using existing components, the adaptees, at run time.DescriptionThis pattern was originally described in [Gamma et al., 1994].
Hence inthis discussion rather than examine the pattern itself in too much detail,we place emphasis on how it can be used on Symbian OS, covering arange of diverse circumstances.The context of this pattern of having to match incompatible interfacescan arise in numerous different situations. Software based on SymbianOS is subject to many pressures all of which can give rise to problemsof mismatching interfaces: it is an evolving system with a large userbase, which means that maintaining interface compatibility from releaseto release is important not just for the operating system itself but alsofor any services and frameworks built on top of it. It targets a domainwhich covers a wide and diverse set of technologies, many of which arestandards-driven and must interoperate, and it is a specialized operatingsystem, carefully evolved to work in a demanding environment.ADAPTER373In addition, you may not be able to change existing components tomake compatible what were incompatible interfaces.