Phlip said:
Your top-level methods should pass values from this
global into their called methods, and these should only rely on the passed
values.
Yes, Phlip (generally value your thoughts, BTW). That was always the
way I've
done it, usually using either constructor parameters or methods like
<associate>
or <adopt>, depending on circumstance... But I've found that I write a
lot of
code that has just that purpose. Also note that Singleton is not good
enough,
as Singleton binds you to implementation (most often), except if the
Singleton's
implementation hides behind a pimpl, but that does not necessarily
allow
polymorphism, although I suppose you could get polymorphism by using
the
bridge pattern - having concrete relationships, these making use of
factories
to achieve what is required. Hmmm, Singletons that make use of
factories to
achieve polymorphism. I suppose that is a solution, yes. OTOH
factories
tend to get sooo complex...
I suppose you could make more valuable contributions (any other
ideas?).
Another idea that struck me was the idea of a Singleton interface, but
no
one seemed to like the idea. I suppose it is too intrusive. It boils
down to this:
#include <cassert>
#include <boost/noncopyable.hpp>
class SingleIFBase : boost::noncopyable
{
protected:
enum eAction{ eCreate, eDestroy, eGet };
};
template <class T>
class SingleIF : SingleIFBase
{
public:
static T& get();
protected:
SingleIF( T& impl );
~SingleIF();
private:
static T* doAction( eAction, T* impl = 0 );
};
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
T* SingleIF<T>::doAction( eAction action, T* impl )
{
static SingleIF* inst( 0 );
if( action == eGet )
{
assert( inst );
}
else if( action == eCreate )
{
assert( inst == 0 );
inst = impl;
}
else
{
assert( action == eDestroy );
assert( inst );
inst = 0;
}
return static_cast<T*>(inst);
}
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
SingleIF<T>::SingleIF( T& impl )
{
SingleIF::doAction( eCreate, &impl );
}
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
SingleIF<T>::~SingleIF()
{
SingleIF::doAction( eDestroy );
}
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
T& SingleIF<T>::get()
{
return (*SingleIF::doAction( eGet ) );
}
.... and is usually used like this (This is an interface
specification):
class MyInterface : public SingleIF<MyInterface>
{
public:
virtual void method1() = 0;
virtual void method2() = 0;
virtual void method3() = 0;
protected:
~MyInterface(){ } //Could be virtual to prohibit compiler warnings
MyInterface(): SingleIF( *this ){ }
};
BTW, I know it does have some caveats that I can think of (slicing at
the
end of its life (an obvious one) ), but in general it seems to reduce
all this
associative code required to get the right "concrete" at the right
place. For
me it seems a simpler solution than factories and in general it works
very well, especially if you want only one instance (or
implementation) of
an interface - something that I've seemed to require often.
Regards,
Werner