From 67523269fcbb1a817c3f4e01194ea8b188334d87 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 29 Sep 2013 03:23:54 +0200 Subject: [PATCH] clean-up and comments for the singleton factory --- src/lib/singleton-factory.hpp | 6 ++--- src/lib/singleton-policies.hpp | 47 +++++++++++++++++----------------- src/lib/singleton.hpp | 31 ++++++++++++++++++++++ 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/src/lib/singleton-factory.hpp b/src/lib/singleton-factory.hpp index cf58818dd..493efb64e 100644 --- a/src/lib/singleton-factory.hpp +++ b/src/lib/singleton-factory.hpp @@ -22,7 +22,7 @@ This code is heavily inspired by The Loki Library (loki-lib/trunk/include/loki/Singleton.h) Copyright (c) 2001 by Andrei Alexandrescu - This Loki code accompanies the book: + Loki code accompanies the book: Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design Patterns Applied". Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 @@ -38,8 +38,6 @@ This code is heavily inspired by #include "lib/singleton-policies.hpp" // several Policies usable together with SingletonFactory #include "lib/nobug-init.hpp" -#include "include/logging.h" -#include "lib/util.hpp" #include "lib/sync-classlock.hpp" namespace lib { @@ -82,7 +80,7 @@ namespace lib { { if (!pInstance_) { - ThreadLock guard SIDEEFFECT; + ThreadLock guard; if (!pInstance_) { diff --git a/src/lib/singleton-policies.hpp b/src/lib/singleton-policies.hpp index 5bfd294d5..feea95b3a 100644 --- a/src/lib/singleton-policies.hpp +++ b/src/lib/singleton-policies.hpp @@ -22,7 +22,7 @@ This code is heavily inspired by The Loki Library (loki-lib/trunk/include/loki/Singleton.h) Copyright (c) 2001 by Andrei Alexandrescu - This Loki code accompanies the book: + Loki code accompanies the book: Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design Patterns Applied". Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 @@ -46,8 +46,8 @@ namespace singleton { /* === several Policies usable in conjunction with lib::Singleton === */ - /** - * Policy placing the Singleton instance into a statically allocated buffer + /** + * Policy to place the Singleton instance into a statically allocated buffer */ template class StaticCreate @@ -91,11 +91,29 @@ namespace singleton { * Policy relying on the compiler/runtime system for Singleton Lifecycle */ template - struct AutoDestroy + class AutoDestroy { + class DeleteTrigger + { + vector dels_; + + public: + void schedule (DelFunc del) + { + dels_.push_back(del); + } + ~DeleteTrigger() + { + vector::iterator del = dels_.begin(); + for ( ; del != dels_.end(); ++del ) + (*del)(); // invoke deleter function + } + }; + + public: /** implements the Singleton removal by calling * the provided deleter function(s) at application shutdown, - * relying on the runtime system calling destructors of static + * relying on the runtime system to call destructors of static * objects. Because this Policy class can be shared between * several Singletons, we need to memorise all registered * deleter functions for calling them at shutdown. @@ -103,23 +121,6 @@ namespace singleton { static void scheduleDelete (DelFunc kill_the_singleton) { - class DeleteTrigger - { - vector dels_; - - public: - void schedule (DelFunc del) - { - dels_.push_back(del); - } - ~DeleteTrigger() - { - vector::iterator i = dels_.begin(); - for ( ; i != dels_.end(); ++i ) - (*i)(); // invoke deleter function - } - }; - REQUIRE (kill_the_singleton); static DeleteTrigger finally; finally.schedule (kill_the_singleton); @@ -128,7 +129,7 @@ namespace singleton { static void onDeadReference () { - throw lumiera::error::Logic ("Trying to access the a Singleton instance that has " + throw lumiera::error::Logic ("Trying to access a Singleton instance that has " "already been released or finished its lifecycle."); } }; diff --git a/src/lib/singleton.hpp b/src/lib/singleton.hpp index 33ccd9fa1..56c3cb6ee 100644 --- a/src/lib/singleton.hpp +++ b/src/lib/singleton.hpp @@ -22,6 +22,12 @@ /** @file singleton.hpp ** Factory for creating Singleton instances. + ** The Singleton Pattern provides a single access point to a class or + ** service and exploits this ubiquitous access point to limit the number of objects + ** of this type to a single shared instance. Within Lumiera, we mostly employ a + ** factory template; the intention is to use on-demand initialisation and a + ** standardised lifecycle. + ** ** This configuration header just pulls in some other implementation headers in ** the right order. The basic class template for creating singletons resides in ** singleton-factory.hpp, besides we need policy classes defining how to create @@ -32,6 +38,31 @@ ** You'll find the default Policies in singleton-factory.hpp and the default ** definition of type lumiera::singleton in singleton-preconfigure.hpp ** + ** \par Why Singletons? Inversion-of-Control and Dependency Injection + ** + ** Singletons are frequently over-used, and often they serve as disguised + ** global variables to support a procedural programming style. As a remedy, typically + ** the use of a »Dependency Injection Container« is promoted. And -- again typically -- + ** these DI containers tend to evolve into heavyweight universal tools and substitute + ** the original problem by metadata hell. + ** + ** Thus, for Lumiera, the choice to use Singletons was deliberate: we understand the + ** Inversion-of-Control principle, yet we want to stay just below the level of building + ** a central application manager core. At the usage site, we access a factory for some + ** service by name, where the »name« is actually the type name of an interface + ** or facade. Singleton is used as an implementation of this factory, when the service + ** is self-contained and can be brought up lazily. + ** + ** \par Conventions, Lifecycle and Unit Testing + ** + ** Usually we place an instance of the singleton factory (or some other kind of factory) + ** as a static variable within the interface class describing the service or facade. + ** As a rule, everything accessible as Singleton is sufficiently self-contained to come + ** up any time -- even prior to \c main(). But at shutdown, any deregistration must be + ** done explicitly using a lifecycle hook. Destructors aren't allowed to do any significant + ** work besides releasing references, and we acknowledge that singletons can be released + ** in \em arbitrary order. + ** ** @see SingletonFactory ** @see singleton::StaticCreate ** @see singleton::AutoDestroy