6
votes

Qui est plus mauvais: un singleton inutile ou un objet de Dieu?

Voici la situation: j'ai une classe qui fait trop. Il est principalement d'accéder aux informations de configuration, mais il a également la connexion à la base de données. Il est mis en œuvre comme un singleton, donc cela rend également le test de l'unité difficile, car la plupart des codes sont assez étroitement couplés. Cela est encore plus problématique car cela crée une dépendance à l'importation (nous le faisons dans Python), ce qui signifie que certains modules doivent être importés dans un certain ordre. Idéalement, je voudrais tous les deux diviser en deux classes et en faire un non-singleton.

Heureusement, mon employeur s'est réchauffé au fait que ce type de test est bon et qui est prêt à me permettre de faire des changements comme celui-ci s'il rend le code plus testable. Cependant, je doute qu'ils soient disposés à me permettre de dépenser trop le temps dessus. Et je préférerais résoudre ce problème de manière incrémentielle plutôt que d'essayer d'être trop radical.

Alors, je vois trois choix ici:

  1. briser l'objet de configuration dans un objet de configuration (singleton) et un objet de base de données (non-singleton). Cela me permettrait au moins de supprimer la base de données comme une dépendance à l'importation.
  2. Faites l'objet de configuration un non-singleton et transmettez-le aux objets qui en ont besoin. Je pense que cela mieux traite nos besoins à court terme, mais je pense que cela prendrait beaucoup plus de temps.
  3. faire quelque chose que je n'avais pas pensé à ce que vous suggérez dans votre réponse. : -)

    Alors, que dois-je faire?


0 commentaires

4 Réponses :


5
votes

Il est difficile de savoir sans voir votre code, mais pourquoi ne pas faire ce que vous dites - faites-le progressivement? Premièrement, Étape 1, divisez la base de données.

Si cela est rapide, revenez, et vous n'avez que 1 objet plus petit pour arrêter d'être un singleton plutôt que 2. SECTION 2 devrait donc être plus rapide. Ou à ce stade, vous pouvez voir un autre code pouvant être refacturé sur le singleton.

Espérons que vous pouvez réduire le pas à pas de savoir ce qui est dans le singleton jusqu'à ce qu'il disparaisse, sans jamais payer de taxe de temps énorme à une étape.

Par exemple, une partie de la configuration peut-être être faite singleton à la fois, si les parties de la configuration sont indépendantes. Donc, peut-être que la configuration GUI a laissé Singleton tandis que la fileconfiguration a refoulé ou quelque chose de similaire?


1 commentaires

Je suppose que est quelque chose que je n'avais pas pensé. En brisant l'objet, il devient plus facile de DE-Singleton (si c'est un mot).



2
votes

L'option 1 est ce que je fais dans toutes mes applications: Objet de configuration Singleton et objets de base de données créés à la demande ou injectés.

Avoir l'objet de cofiguration comme un singleton a toujours été un ajustement parfait pour moi. Il n'y a qu'un seul fichier de configuration et je souhaite toujours la lire lorsque l'application commence.


2 commentaires

Mais c'est là que nous rencontrons des problèmes. Nous voulons lire le fichier de configuration au début de l'application, mais si l'objet de configuration est global, comment arrêtez-vous l'autre code d'essayer d'y accéder avant son initialisation? Je trouve que c'est beaucoup plus difficile à prévenir que cela ne sonne.


Je suis accompli que, en effectuant des propres accessibles sur le Singleton Static et de mettre toutes les classes de configuration Initialistaion Logic dans son constructeur statique. Cela signifie que dès que la première tentative est faite pour accéder à toute propriété sur l'objet de configuration, elle s'initialisera elle-même. J'utilise cette approche avec C # et je ne sais pas si Python a la même approche avec des propriétés et des constructeurs statiques.



5
votes

Je pense que vous êtes sur la bonne voie pour séparer deux classes. Vous voudrez peut-être envisager d'utiliser une usine pour créer votre contexte / connexion de base de données au besoin. De cette façon, vous pouvez traiter la connexion comme unité d'entité de travail créée / disposée au besoin plutôt que de conserver une connexion unique autour de la durée de vie de l'objet. Ymmv, cependant.

Quant à la configuration, c'est un cas où je trouve qu'un singleton peut être le bon choix. Je ne voudrais pas nécessairement le jeter juste parce qu'il est difficile de tester un appareil. Vous voudrez peut-être envisager de la construire, cependant, de mettre en œuvre une interface. Vous pouvez ensuite utiliser une injection de dépendance pour fournir une instance simulée de l'interface pendant les tests. Votre code de production serait construit soit pour utiliser l'instance Singleton si la valeur injectée est null ou pour injecter l'instance Singleton. Sinon, vous pouvez construire la classe pour permettre la réinitialisation via une méthode privée et l'invoquer dans vos méthodes de test de configuration / dératrement afin de vous assurer qu'elle dispose de la configuration appropriée pour vos tests. Je préfère le premier à la dernière mise en œuvre, même si je l'ai utilisé aussi lorsque je n'ai pas de contrôle direct sur l'interface.

Rendre les changements incrémentellement est définitivement la voie à suivre. Enroulant la fonctionnalité actuelle avec des tests, si possible, et assurez-vous que ces tests passent toujours après vos modifications (cependant, pas les celles qui s'occupent directement de vos modifications, bien sûr) est un bon moyen de vous assurer que vous ne brisez pas d'autre code .


0 commentaires

2
votes

Excusez le fait que je ne connais pas de python, j'espère donc que tout pseudo code a du sens ...

Je partagé d'abord l'objet en deux parties afin que les responsabilités de votre singleton soient plus petites, puis Je prendrais la configuration restante singleton et la modifierais en une classe normale (comme si vous allez effectuer votre deuxième suggestion). P>

Une fois que j'aurais été aussi loin que je créerais un nouveau wrapper singleton qui expose les méthodes de la classe de configuration: p> xxx pré>

La toute première chose que l'application est injecte une instance de la classement de configuration dans l'emballage. P>

ConfigurationClass config = new ConfigurationClass()
ConfigurationWrapper.Instance.InnerClass = config;


0 commentaires