Revenons sur mon exemple « conceptuellement insensé »… :roll: :P
On dispose d'une hiérarchie de classes (ou d'une classe seule) qui ont une sémantique de valeur.
Mais, pour des raisons que je ne vais pas exposer, on va leur donner une sémantique d'entité ; ceci permettra entres autres de faire des comparaisons sur des adresses plutôt que sur des objets.
Du coup, on ne peut plus laisser l'utilisateur créer des objets comme il le veut (ni les détruire).
Il nous faut donc une interface qui, en fonction des paramètres qu'on lui passe, crée l'objet correspondant s'il n'existe pas déjà, et retourne l'adresse de l'unique instance.
Une sorte de mix entre une « fabrique » et un « singleton », si l'on veut… :D
Bien entendu, la manière de gérer tout ça doit être transparente pour l'utilisateur.
Alors si j'ai bien compris ce que vous m'avez dit, je devrais faire quelque chose comme ce qui suit (sur le principe) ?
En passant, c'est indispensable que la classe de base soit abstraite ?
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
| struct deleter
{
void operator () (void* p)
{ delete p; }
}; // struct deleter
//*****************************************************//
class base
{
friend
class base_generator;
protected:
base(...) {...}
virtual
~base() {...}
private:
base(const base&);
base& operator = (const base&);
(...)
}; // class base
class base_generator
{
friend
class base_manager;
private:
static
base* create(...)
{
(...)
return new base(...);
}
base_generator();
base_generator(const base_generator&);
~base_generator();
base_generator& operator = (base_generator&);
}; // class base_generator
class base_manager
{
private:
typedef std::container<base*> container;
typedef container::iterator iterator;
static
base_manager collection_;
container instances_;
static
void insert(base* obj)
{ return collection_.insert(obj); }
public:
static
bool contains(...)
{ return __contains__(collection_, ...); }
static
base* find(...)
{ return __find__(collection_, ...); }
static
void clear()
{ return collection_.clear(); }
static
base* instance(...)
{
if contains(...)
return find(...);
base* tmp = base_generator::create(...);
insert(tmp);
return tmp;
}
private:
base_manager() : instances_()
{}
~base_manager()
{ clear(); }
base_manager(const base_manager&);
base_manager& operator = (const base_manager&);
iterator begin()
{ return instances_.begin(); }
iterator end()
{ return instances_.end(); }
void insert(base* obj)
{ instances_.__insert__(obj); }
bool contains(...)
{ return __contains__(instances_, ...); }
base* find(...)
{ return __find__(instances_, ...); }
void clear()
{
std::for_each(begin(), end(), deleter());
return instances_.clear();
}
}; // class base_manager |
Sinon, les classes internes sont-elles susceptibles de remettre en question le principe de responsabilité unique ?
C'est vrai que si on modifie la classe A::B, en quelque sorte on modifie également (indirectement) la classe A, mais pour autant les modifications de A::B n'ont
a priori aucune répercussion sur A.
Je me trompe peut-être, mais j'ai tendance à voir la classe A comme l'espace de nom de la classe A::B, si ce n'est qu'il est possible de définir sa visibilité hors de cet espace de nom.
Je demandais ça pour savoir s'il y a un moyen de ne pas exposer « base_generator » et « base_manager ».