8
votes

Refactoring une classe statique pour séparer son interface de la mise en œuvre

Je travaille sur une application basée sur .NET, où certaines des classes d'applications principales ont été conçues avec uniquement les méthodes statiques em>.

Exemple d'utilisation: P>

// static access.
Parameters.GetValue("DefaultTimeout");

// static access.
Logger.Log("This is an important message!");
  • Comment puis-je transformer facilement des objets avec un accès statique uniquement à une conception basée sur une interface, de sorte que leur mise en œuvre puisse être remplacée en cas de besoin (mais gardant l'accès statique). P> LI>

  • Une fois refactored, comment / quand l'injection réelle de la mise en œuvre non par défaut devrait se produire? p> li> ol> p>


  • 2 commentaires

    "Il y a déjà un code là-bas qui utilise ces méthodes statiques, de sorte que cette" interface "ne peut pas être modifiée." - Est-ce tout à fait vrai? Un changement de rupture ne se casse que si le code qui l'utilise n'est pas mis à jour également. Pourquoi ce code ne peut-il pas être mis à jour? "J'aimerais pouvoir séparer la mise en œuvre réelle de ces classes de leur interface." - Cela vaut vraiment la peine de faire, mais dans votre cas, cela peut être un effort important. Tout ce "autre code" susmentionné est étroitement associé à la mise en œuvre. Briser cet accouplement nécessite de modifier ce code.


    Si c'est statique, ce n'est pas un objet


    3 Réponses :


    6
    votes

    Pour chaque méthode statique, créez une instance. Ajoutez une variable statique singleton que vous pouvez attribuer n'importe quelle implémentation à. Rendre les méthodes statiques appelez les méthodes d'instance sur le singleton statique.

    Cela vous permettra d'échanger la mise en œuvre au moment de l'exécution, mais vous ne pouvez avoir qu'une seule implication accrochée en même temps.

    Le code existant n'a pas besoin de changer.


    3 commentaires

    C'est ce que je pensais. Qu'en est-il de la question du moment où cette accrochable a lieu?


    Cela dépend de ce que vous voulez faire. Peut-être que tout configure tout au démarrage, peut-être utiliser un threadstatique, peut-être utiliser httpcontext.current.items comme support de support. Qu'est-ce que tu veux faire?


    Par exemple, je voudrais utiliser la configuration de démarrage si je devais configurer un enregistreur ou lire web.config.



    12
    votes

    Disclaimer: La suggestion suivante est basée sur l'importance de ne pas changer le côté appel. Je ne dis pas que c'est la meilleure option, juste que je pense que c'est approprié.

    Déconnecter la mise en œuvre

    Il n'y a aucun moyen d'avoir des interfaces sur les membres statiques, donc si vous ne voulez pas changer Le code d'appel, la statique devra probablement rester. Cela dit, vous pouvez simplement avoir votre classe statique enveloppe une interface à l'intérieur, de sorte que la classe statique elle-même n'a pas de mise en œuvre - il délègue tous les appels à l'interface. < / P>

    Tout cela signifie que vous pouvez laisser votre classe statique et n'importe quel code qui l'appelle en place. Ce sera comme traiter la classe statique comme interface (ou contrat), mais la présentant de la mise en œuvre interne en interne en fonction de la situation.

    Cela signifie également que votre interface peut avoir une signature différente de la classe statique, Comme l'interface ne doit pas être conforme aux attentes du code d'appel - fondamentalement, elle transformera votre classe statique en une sorte de Bridge .

    Injection de la mise en œuvre

    En bref: Utilisez un constructeur statique afin de résoudre l'implémentation donnée de cette interface.

    Les statiques sont par appdomaine normalement (sauf décorées avec threadstaticattribute , puis par appdomain / thread) afin que vous puissiez déterminer où vous êtes et quelle implémentation dont vous avez besoin sur la base de l'appdomain actuel (le constructeur statique sera appelé chaque fois que la statique est utilisée pour la première fois dans l'AppDomain). Cela signifie qu'une fois construit, que la mise en œuvre enveloppée d'une classe statique particulière restera pendant la durée de l'AppDomain (bien que vous puissiez mettre en œuvre des méthodes pour rincer la mise en œuvre).

    Cross AppDomain appelant

    Le code responsable de cette option peut être dans les classes statiques ou vous pouvez créer une des implémentations d'interface simplement un gestionnaire proxy à un type d'appdomain. Tout type de cross AppDomain appelle aura besoin d'hériter MarshalbyRefObject .

    http://msdn.microsoft.com/en-us/library/ms173139.aspx

    CreateInstance d'un type dans une autre AppDomain

    moyen le plus simple de faire appeler-AppDomain appeler?

    Exemple d'application < / p>

    Vous devriez simplement être capable de copier et de coller cela dans une nouvelle demande de console. Ce que cela fait consiste à enregistrer une implémentation pour l'appdomaine par défaut et une pour les AppDomains fabriqués par l'utilisateur. La valeur par défaut crée simplement une implémentation à distance de l'interface (dans l'autre AppDomain). Juste pour démontrer l'idée "statique par AppDomain", le délégué de mise en œuvre à distance à une autre mise en œuvre pour les domaines non par défaut.

    Vous pouvez modifier les implémentations à la volée, tout ce que vous devez modifier est le constructeur de classe statique. (Pour décider de quelle implémentation choisir). Notez que vous n'avez pas besoin de changer la méthode principale , notre code d'appel dans ce cas. xxx

    une note sur la durée de vie < / strong>

    L'un des principaux problèmes de gestion d'un refactoring de classes statiques n'est généralement pas le changement du code client (car cela est soutenu par de nombreux outils de refactoring et il existe des techniques pour le faire faire en toute sécurité), mais gérer la durée de vie de l'objet. Les objets d'instance s'appuient sur des références vivantes (sinon elles sont des ordures recueillies), elles peuvent généralement être rendues «facilement accessibles» en conservant un membre statique public quelque part, mais c'est généralement ce que vous essayez d'éviter en refractant en premier lieu.

    Il ne semble pas que vous faudriez vous inquiéter de cette préoccupation, car vous quittez le code d'appel attaché aux classes statiques, la durée de vie restera la même.


    2 commentaires

    Merci pour la réponse détaillée. Je ne suis pas sûr de suivre votre exemple avec les appdomions par défaut par défaut par défaut (car ce n'est pas exactement le cas d'utilisation que j'étais après) mais cela n'a pas vraiment d'importance dans le contexte de cette question. Mes commentaires sont les suivants: 1. Le refactoring Les clients sont faciles avec le support de l'outil, mais la plupart du code sont déjà déployés et non contrôlés par moi, ce qui rend plus difficile le refracteur. 2. Je me demande si l'initialisation de la mise en œuvre dans le constructeur statique peut être développée davantage par des cadres IOC pour pouvoir sélectionner différentes implémentations de manière plus flexible.


    @ lysergique-acide ok je n'ai pas réalisé que le code était hors de votre contrôle. Vous pourrez peut-être utiliser un cadre IOC, mais uniquement s'ils exposent un conteneur statique que vous pouvez accéder. C'est une idée fausse qu'ils offrent plus de flexibilité, à la fin de la journée, vous pouvez mettre en œuvre tout ce que vous souhaitez déterminer la mise en œuvre. Les cadres de la COI viennent de faire beaucoup de plomberie déjà. Désolé, cela n'a pas répondu à votre cas d'utilisation, mais d'être juste, ce n'était pas dans la question.



    3
    votes

    Les classes statiques peuvent être transformées en objets Singleton.

    Objets Singleton Les interfaces prennent des interfaces. p>

    interfaces peut être utilisé pour différentes implémentations. p>

    (1) Définition du problème. strong> p>

    Supposons que vous ayez une classe qui a une classe Membres statiques. p>

    - p>

    stringclass.cs p>

    - p> xxx pré>

    - p>

    et, plusieurs code qui utilise ces éléments statiques, de cette classe. p>

    - p>

    stringslibryuser.cs p>

    - P >

    using Libraries;
    
    namespace MyApp
    {
      public class AnyClass
      {
        public StringsInterface StringsHelper = StringsClass.getInstance().LowercaseCopy(Example);
    
        public void AnyMethod()
        {
          string Example = "HELLO EARTH";
          string AnotherExample = StringsHelper;
        } // void AnyMethod(...)  
    
      } // class AnyClass
    
    } // namespace MyApp
    


    0 commentaires