Refactoring - Risolvi le dipendenze tra il codice legacy utilizzato da terze parti

-1

Sto sviluppando due librerie in .Net

Firs one è una libreria con funzionalità di base (denominata Library.Core.dll)

Concentriamoci sulla classe utente

public class User
{
     //set of constructors and methods
     public void LogOff()
    {
        //does not know the functionality
    }
}

Nell'altra libreria sto implementando altre funzionalità (chiamiamole Library.Functionalities.dll) e voglio implementare il metodo LogOff della classe User. Quindi, ogni volta che Utente è istanstiated ha implementato il metodo LogOff.

Library.Core non deve dipendere da nulla (evitando dipendenze circolari

Importante : le librerie vengono attualmente utilizzate da più applicazioni, quindi la creazione di nuovi costruttori (con l'integrazione delle dipendenze) in Library.Funcionalities.dll non è possibile (per quanto ne so). Devo rispettare il modo in cui gli altri stanno usando la libreria, quindi non rompere nulla, ma devo assicurarmi che tutti eseguano il codice che voglio in LogOff.

Che cosa suggerisci? Se hai bisogno di ulteriori spiegazioni, dimmi!

    
posta Badulake 28.09.2017 - 08:07
fonte

3 risposte

0

Tali requisiti non possono essere soddisfatti con codice pulito, credo. C'è una possibilità tecnica, ma ha alcuni odori:

Definisci un'interfaccia ILogOff con una funzione void LogOff(User user) nella libreria core e scrivi alcune implementazioni nella libreria functionalities .

Crea un ServiceLocator nella libreria core , rendilo static . Quando viene creato ServiceLocator , legge un file di configurazione e crea le classi per riflessione (quindi possono essere localizzate in qualsiasi altra libreria).

Cambia la funzione Logoff in:

public void LogOff()
{
    ILogOff logOff = ServiceLocator.GetLogOff();
    logOff.LogOff(this);
}

Questa non è una grande soluzione. Analizzalo e scopri se vuoi davvero andare in quel modo.

    
risposta data 28.09.2017 - 10:52
fonte
0

Se:

  1. Non puoi aggiornare Core
  2. Non puoi aggiornare le altre applicazioni
  3. Le altre applicazioni creano utenti tramite new Library.Core.User(...)

Quindi, no. Non è possibile modificare il comportamento del metodo LogOff . Sei bloccato.

    
risposta data 28.09.2017 - 18:08
fonte
0

OP, non riesco ancora a comprendere appieno il tuo progetto, ma ritengo che i tuoi obiettivi siano:

  1. Spiana la strada per aggiornamenti occasionali alla tua logica aziendale
  2. Riduci al minimo l'impatto su applicazioni di terze parti che già fanno riferimento a una delle tue DLL, Library.Core.dll .

Il tuo piano attuale sembra essere quello di distribuire un'altra DLL fianco a fianco con Library.Core.dll e lasciare invariato la DLL originale. Questo non funzionerà. A meno che una DLL non sia specificatamente codificata per permetterlo, un'altra DLL non può sovrascrivere la sua funzionalità - questo sarebbe un grosso onere per gli sviluppatori e causerebbe un rischio per la sicurezza, dato che chiunque potrebbe mettere una DLL là fuori che rompe un'applicazione, potenzialmente in un modo malevolo.

Quindi dovrai rilasciare almeno una nuova versione di Library.Core.dll . Se si utilizzano lo stesso numero di versione e la chiave di firma, i client non dovranno ricompilare. Oppure, se desideri aumentare il numero di versione (generalmente consigliato), puoi dire ai tuoi clienti di utilizzare un redirect binding se non si desidera ricompilare.

Considerato quanto sopra, il nuovo piano è

  1. Scrivi una nuova versione di Library.Core.dll che è identica all'interfaccia dell'originale. Questa DLL deve supportare funzionalità future senza dover essere modificata.
  2. Scrivi una nuova rete Library.Functionalities.dll che conterrà l'implementazione. Potresti finire per rilasciare nuove versioni di questo in futuro.

Ecco come farei al riguardo:

Innanzitutto, scrivi Library.Functionalities.dll usando le moderne tecniche IoC, introducendo nuovi costruttori secondo necessità ma mantenendo il modello di oggetto originale.

In secondo luogo, scrivi un nuovo Library.Core.dll che sarà una facciata a Library.Functionalities.dll . Ecco un esempio:

[assembly:InternalsVisibleTo("Library.UnitTests")]
namespace Library.Core
{
    class User
    {
        private readonly IUser _innerUser;

        public User() : base (Factory.Resolve<IUser>());  //For public consumption

        internal User(IUser innerUser) //For your unit testing projects        
        {
            _innerUser = innerUser;
        }

        public void LogOff()
        {
            _innerUser.LogOff();  //Wrap the inner user object
         }
    }

    internal class Factory
    {
        private static MyIoCContainer _container = new MyIoCContainer(); //AutoFac, Unity, Ninject, whatever

        static Factory() //Composition root here
        {
            ContainerBuilder builder = new ContainerBuilder();
            Library.Functionalities.Application.RegisterDependencies(builder);
            _container = builder.Build();
        }

        static public T Resolve<T>()
        {
            return _container.Resolve<T>(); 
        } 
    }
}

E in Library.Functionalities.dll:

namespace Library.Functionalities
{
    public class Application
    {
        static void RegisterDependencies(ContainerBuilder builder)
        {
            builder.RegisterType<IUser, User>();
        }
    }
}

Nell'esempio precedente, Library.Core.User è solo un involucro sottile per Library.Functionalities.User . Se il chiamante lo costruisce usando il vecchio metodo (senza iniezione), sostituirà un'iniezione predefinita da una fabbrica.

Puoi scrivere la fabbrica come preferisci. Nel mio esempio utilizzo un semplice approccio al contenitore IoC.

Quando hai finito, la risoluzione effettiva della dipendenza su User è nascosta al client, che può continuare a fare riferimento a Library.Core.dll , completamente inconsapevole che sta parlando solo con una facciata.

Quando hai nuove funzionalità da distribuire, puoi semplicemente aggiornare Library.Functionalities.dll e, se hai codificato correttamente la fabbrica, la nuova versione dovrebbe essere prelevata automaticamente. E sarai comunque in grado di utilizzare tutte le moderne tecniche IoC, iniettare shim per il test delle unità, ecc.

    
risposta data 28.09.2017 - 18:42
fonte