2010-05-05 7 views
6

La plupart des programmes que j'écris sont des processus relativement à flux, avec un début défini et une fin espérée. Les problèmes eux-mêmes peuvent être complexes mais ne se prêtent pas facilement à l'utilisation centralisée des objets et à la programmation événementielle. Souvent, je suis simplement en train de parcourir de nombreux lots de données textuelles variées pour produire différentes données textuelles. Par exemple, pour suivre les avertissements, les erreurs et le message de débogage, j'ai créé une classe (Problems) avec une instanciation (myErr), ce que je crois être un exemple du modèle de conception Singleton. . Comme autre facteur, mes collègues sont plus old school (procédural) que moi et ne connaissent pas la programmation orientée objet, donc je répugne à créer des choses qu'ils ne pourraient pas résoudre. Et pourtant j'entends, encore et encore, que même le motif de conception de Singleton est vraiment un anti-pattern et qu'il devrait être évité car Global Variables Are Bad.Veuillez décrire vos difficultés en minimisant l'utilisation des variables globales

Les fonctions mineures ont besoin de peu d'arguments et n'ont pas besoin de connaître la configuration (immuable) ou l'état du programme (changement) - Je suis d'accord. Cependant, les fonctions au milieu de la chaîne, qui contrôlent principalement le déroulement du programme, ont besoin d'un grand nombre de variables de configuration et de certaines variables d'état du programme. Je crois que passer une douzaine ou plus d'arguments à une fonction est une «solution», mais guère attrayante. Je pourrais, bien sûr, entasser des variables dans un seul tableau de hachage/dict/associative, mais cela ressemble à de la triche. Par exemple, en me connectant à Active Directory pour créer un nouveau compte, j'ai besoin de telles variables de configuration comme nom d'utilisateur administratif, mot de passe, unité d'organisation cible, certains groupes par défaut, domaine, etc. Je devrais passer ces arguments par le biais d'une variété de fonctions qui ne les utiliseraient même pas, il suffit de les mélanger à travers une chaîne qui mènerait finalement à la fonction qui en a réellement besoin. Je voudrais au moins déclarer les variables de configuration comme étant constantes, pour les protéger, mais la langue de mon choix de nos jours (Python) ne fournit pas une manière simple de le faire, bien que des recettes existent comme solutions de contournement.

Nombreuses questions de dépassement de pile ont frappé sur le pourquoi? de la méchanceté et l'évitement requis, mais ne mentionnent pas souvent des conseils sur la vie avec cette restriction quasi-religieuse. Comment avez-vous résolu, ou au moins fait la paix avec, la question des variables globales et de l'état du programme? Où avez-vous fait des compromis? Quelles ont été vos astuces, en dehors du fait de déplacer des groupes d'arguments vers des fonctions?

+0

Bonne question - catégorisez-vous les variables de niveau classe (membre) comme variables globales? –

Répondre

5

Je pense qu'il y a un temps et un endroit pour le motif singleton, ou des situations similaires. Le point clé à retenir est que maintes et maintes fois, de nombreuses personnes ont expérimenté une horreur spécifique quand il s'agit du «mauvais» choix d'utiliser des variables globales/partagées/statiques ainsi que le modèle singleton.

Dans votre cas, vous parlez de la configuration en particulier. Je ne vois pas de mal à utiliser un modèle de style singleton pour l'accès à ces éléments de configuration. Chaque application a une configuration, il DEVRAIT être dans un endroit que vous pouvez appeler, il n'est pas nécessaire de simplement le faire circuler, ce qui complique plus que cela ne l'aide.

La clé ici est de s'assurer que vous avez vraiment besoin que l'information n'existe qu'une seule fois, la configuration est de loin l'une des meilleures raisons que j'ai trouvé pour utiliser ce type de modèle.

3

Les données globales qui sont immuables ou bien définies à l'échelle du processus (par exemple, la consignation) peuvent généralement être utilisées comme données globales. Les données de configuration, en particulier si elles résident dans un fichier local, appartiennent à la même catégorie (il n'y a qu'un seul fichier pour l'ensemble du processus/de l'application, similaire à la journalisation).

En général, si vous trouvez que vous devez passer des arguments supplémentaires juste pour les passer à une autre fonction, vous devriez tirer cette fonction vers le haut et en avoir une autre qui intervient. Une autre approche, plus pratique, qui illustre cela est le développement piloté par les tests car il vous oblige à transmettre des dépendances. Une autre manière d'y penser est: si cette fonction ne peut pas facilement connaître tous les détails pour appeler une sous-fonction, tirez la sous-fonction vers le haut, et forcez une couche plus haute, plus savante, pour acquérir le nécessaire information. J'ai trouvé cette technique très conductrice de la qualité du code, car elle construit des pièces compartimentées, au lieu de bêtes monolithiques.

Dans votre exemple au sujet de répertoire actif, au lieu de passer autour des arguments à la ad_connect, passer autour d'un objet qui gère la logique nécessaire, ont alors une fonction qui médie l'interaction entre le cet objet et la fonction de l'utiliser

def create_user(name, ad_user, ad_pass, ad_ou, ...): 
    conn = ad_connect(ad_user, ad_pass, ...) 
    conn.CreateRecord(ad_user) 

def create_user_mediator(name, ad_controller): 
    ad_controller.CreateRecord("cn=%s" % name) 

C'est juste une façon de le faire, et, bien sûr, a ses avantages et ses inconvénients. C'est simplement un exemple de comment create_user peut éviter d'avoir à utiliser des variables globales.