Pour le développement de Pyxoo je suis souvent confronté à la création de classes qui ne doivent proposer qu’une seule instance d’elles-même. La solution du Singleton semble bien évidemment la plus pertinente pour répondre à ce problème.
Malgré les différentes solutions trouvées sur la toile ici ou là, un problème persiste en python : il est impossible de rendre privé un contructeur de classe comme en java.
Pour celà, un petit hack existe :
class MaClasse:
__instance = None
class __PRIVATE:pass
@classmethod
def getInstance(cls):
if cls.__instance is None: cls.__instance = MaClasse(cls.__PRIVATE)
return cls.__instance
def __init__(self, privateAccess):
if privateAccess is not self.__PRIVATE:
raise Exception("Contructeur privé")
#Pour recuperer l'instance de la classe :
o = MaClasse.getInstance()
Nous venons de voir une manière simple de rendre privé le constructeur d’une classe et donc par la même occasion le design pattern Singleton qui, je le rappelle, fait partie de la famille “Création”.
Un avantage de cette méthode est la méthode statique getInstance() qui permet au premier coup d’oeil de comprendre qu’il s’agit d’un Singleton.
Un autre motif de conception peu connu mais néanmoins utile : le Multiton. Ce dernier est une sorte de singleton mais associé à une clé passée en paramètre de la méthode getInstance().
Un exemple concret de multiton est le ModelLocator implémenté dans la librairie Pyxoo. Un ModelLocator est associé à un Plugin passé en paramètre.
Voici un autre exemple d’implémentation du design pattern Multiton :
class MaClasse:
__instances = dict()
class __PRIVATE:pass
@classmethod
def getInstance(cls, unObjet):
if unObject not in cls.__instances:
cls.__instances[unObjet] = MaClasse(cls.__PRIVATE)
return cls.__instances[unObjet]
def __init__(self, privateAccess):
if privateAccess is not self.__PRIVATE:
raise Exception("Contructeur privé")
#Pour recuperer une instance de la classe
o1 = MaClasse.getInstance( "A1" )
o2 = MaClasse.getInstance( "A1" )
o3 = MaClasse.getInstance( "A2" )
id(o1) == id(o2) #retourne vrai
id(o1) == id(o3) #retourne faux
Une méthode statique release() peut souvent être utile dans les deux cas présentés ci-dessus. En effet, il peut être nécessaire de réinitialiser l’instance.
class MaClasse:
__instance = None
class __PRIVATE:pass
@classmethod
def getInstance(cls):
if cls.__instance is None:cls.__instance = MaClasse(cls.__PRIVATE)
return cls.__instance
def __init__(self, privateAccess):
if privateAccess is not self.__PRIVATE:
raise Exception( "Constructeur privé")
@classmethod
def release(cls):
cls.__instance = None
Comme vous pouvez le constater cette méthode réinitialise l’instance de la classe.
Voilà, c’est fini pour ce petit tutoriel, en espérant vous avoir été utile dans la compréhension de ces deux Design Pattern.
