Quando devo utilizzare classi astratte rispetto interfacce per quanto riguarda l’Iniezione di dipendenza?

Ho letto alcuni articoli su SOLIDI principi e di dipendenza Inversione. Dal mio punto di vista, devo usare un’interfaccia per parlare di qualsiasi classe. Le mie lezioni sono in chat utilizzando interfacce.

Prima Domanda:

Sto usando una classe astratta, ma per la seconda parte del mio codice, l’utilizzo di un’Interfaccia.

Usage1


namespace DependencyInjection
{

    public interface IMessage
    {

    }
    public abstract class Message
    {
        public abstract void Get();
        public abstract void Send();
    }

    public class Sms : Message, IMessage
    {
        public override void Get()
        {
            Console.WriteLine("Message Get!");
        }
        public override void Send()
        {
            Console.WriteLine("Message Send!");
        }
    }

    public class MessageManager
    {
        private IMessage _message;

        public Sms Sms
        {
            get { return _message as Sms; }
            set { _message = value; }
        }

        public MessageManager(IMessage message)
        {
            _message = message;
        }

    }
}

Uso:



    class Program
    {
        static void Main(string[] args)
        {
            MessageManager msg = new MessageManager(new Sms());
            msg.Sms.Get();
            msg.Sms.Send();
            Console.Read();
        }
    }

Usage2


namespace DependencyInjection
{

    public interface IMessage
    {
        public  void Get();
        public  void Send();
    }


    public class Sms :  IMessage
    {
        public  void IMessage.Get()
        {
            Console.WriteLine("Message Get!");
        }
        public  void IMessage.Send()
        {
            Console.WriteLine("Message Send!");
        }
    }

    public class MessageManager
    {
        private IMessage _message;

        public Sms Sms
        {
            get { return _message as Sms; }
            set { _message = value; }
        }

        public MessageManager(IMessage message)
        {
            _message = message;
        }

    }
}

Qual è la differenza tra Usage1 e usage2? Quando devo scegliere usage1 o Usage2?

  • Quindi, se l’esempio di proprietà classe astratta Message per essere ereditato, come un int ID e string Sender per esempio, sarebbe il modo più pulito abbia Message : IMessage per ereditare i metodi e quindi di inserire un oggetto del Messaggio: public MessageManager(Message message)? Chiedo solo se è scarsa pratica per qualche motivo, perché non mi capita spesso DI vedere con le classi.
InformationsquelleAutor loki | 2012-11-18



6 Replies
  1. 22

    Classi astratte qui a combattere con codice duplicato. Interfacce – definire contratti (API).

    Dipendono interfacce – semplicemente descrivere contratto (API) di dipendenza, e si può beffare facilmente. Quindi, iniziare con interfaccia:

    public interface IMessage
    {
        void Get(); //modifiers like public are not allowed here
        void Send();
    }

    E qui è la vostra classe dipendente, che deve dipendere solo dalle astrazione (cioè interface):

    public class MessageManager
    {
        private IMessage _message;
    
        //depend only on abstraction 
        //no references to interface implementations should be here
        public IMessage Message
        {
            get { return _message; }
            set { _message = value; }
        }
    
        public MessageManager(IMessage message)
        {
            _message = message;
        }
    }

    Quindi creare la classe che implementa l’interfaccia:

    public class Sms : IMessage
    {
        //do not use explicit implementation 
        //unless you need to have methods with same signature
        //or you want to hide interface implementation
        public void Get()
        {
            Console.WriteLine("Message Get!");
        }
    
        public void Send()
        {
            Console.WriteLine("Message Send!");
        }
    }

    Ora avete inversa dipendenze – MessageManager e Sms dipende solo IMessage. Si può iniettare IMessage implementazioni MessageManager (MessageManager ora fit OCP – aperto per estensione, ma chiuse per la modifica).

    Creare la base astratta classe di messaggio solo quando si dispone di codice duplicato in diversi IMessage implementors. Quando si crea classe astratta (luogo, dove ci si sposta codice duplicato), si consiglia di non cambiare interfaccia, perché il contratto rimane lo stesso. Basta ereditare la classe base da originale IMessage interfaccia.

    • Mi sono imbattuto in un problema simile e ha finito per cambiare la mia interfaccia di una classe astratta che le altre classi sono dipendente… Invece ho creato una classe Astratta che implementa l’interfaccia e poi le mie altre classi ereditano da essa?
    • Io di solito inizio con l’interfaccia. In realtà quando si esegue fuori di sviluppo, si ha sempre l’interfaccia di profonda oggetti prima di iniziare a scrivere di loro. Le interfacce sono completamente mockable, questo è anche un vantaggio. Quando ho diverse classi che implementano l’interfaccia E hanno duplicato di codice (dati o metodi), poi ho estratto base di classe delle classi, e fare di base di classe implementa l’interfaccia originale. Se la classe base non è utilizzato, quindi faccio un riassunto. Quindi sì, classe astratta di solito deve implementare l’interfaccia e l’altra le classi ereditano da essa.
  2. 2

    Originale definizione di un’interfaccia è una classe astratta con tutti i metodi virtuali puri (cioè i metodi astratti), questo è come descrivere un’interfaccia in C++. Se non la creazione di funzioni virtuali con le definizioni default quindi davvero non c’è bisogno di una classe astratta a tutti. Se si dispone di alcune funzionalità predefinita che si vorrebbe che i bambini della classe di Messaggio di ereditare (e permettere di ignorare o non), e poi si usa una classe astratta. Una classe astratta può anche definire metodi protetti e/o le proprietà e i campi, questi possono essere utilizzati dalle classi che ereditano dalla classe astratta, ma non per le classi che utilizzano la classe astratta. Tutti i metodi di un’interfaccia sarebbe pubblici. Nel caso In cui si ha disposto una interfaccia andrebbe bene.

  3. 1

    basato su quello che vedo non si è fatto uso di un’interfaccia. Sicuro che implementano i metodi, ma il consumo di classe, non dovrebbe davvero sapere o cura l’attuazione. Pertanto, si dovrebbe davvero vedere qualsiasi riferimento o casting per Sms. Si dovrebbe essere utilizzando un framework IoC Unità, Ninject, structuremap. Se hai veramente bisogno di una proprietà pubblica e la restituzione di un IMessage, dovrebbe tornare IMessage e non gli Sms, se si dovrebbe fare, che è diverso conversazione.

    Che ha detto, il primo Utilizzo, non ha nulla in IMessage, quindi è inutile. Anche io uso spesso un abstract /classe di base per gestire le funzionalità più comuni tra le varie implementazioni di un’interfaccia. In voi scenario, non c’è bisogno per la classe astratta. L’unica volta che mi creo i metodi astratti senza codice è se la classe astratta in realtà incendi che metodo in alcune capacità, ma si aspetta che la classe derivata per implementare la funzionalità.

    Comunque, per rispondere domanda di Utilizzo #2 sembra più vicino alla soluzione corretta, ma solo di rimuovere i riferimenti a Sms e lasciare che l’IoC container in grado di gestirlo.

  4. 1

    Un interfaccia non contengono il codice di implementazione e non forza l’implementatore di derivare la sua attuazione modulo di una data classe. Una classe base astratta o non) possono già contenere un po ‘ di logica. Questo può essere un vantaggio, così come un indesiderabile vincolo.

    Naturalmente è possibile combinare entrambi gli approcci. Definire e programmare un’interfaccia e al tempo stesso di fornire una base di classe (o più classi base) implementazione di questa interfaccia e provare alcuni di base di logica che semplifica un implementatori di attività. Una persona che implementa l’interfaccia può decidere di andare in modo facile, e di estendere una classe di base per creare qualcosa di completamente nuovo e implementare l’interfaccia direttamente.

    L’ .NET Framework class library fornisce le classi base per collezioni come Collection<T> o KeyedCollection<TKey,TItem> implementare IList<T> che è possibile utilizzare come base per la creazione della propria raccolta specializzata. Ma, naturalmente, si può iniziare da zero e implementare IList<T> direttamente.

  5. 1

    Il motivo per scegliere una classe astratta su una interfaccia ha a che fare con il codice riutilizzabile. Il fatto che si sta utilizzando l’iniezione di dipendenza non cambia questa risposta.

    Fare tutte le sottoclassi hanno in comune la funzionalità? Se è così, non può essere definita nella classe base.

    Dovrebbe il metodo di modello di modello di progettazione essere utilizzato? Se è così, l’algoritmo esiste nella classe base.

    Come sempre, la risposta è: “dipende”. Non si può fare di questi approcci con le interfacce interfacce specificare solo il contratto e di non avere attuazione. Se il contratto è tutto ciò di cui avete bisogno, allora vai con un’interfaccia. Se avete bisogno di un codice per essere condiviso dalle sottoclassi, poi andare con una classe astratta.

  6. 1

    Non ho molto da aggiungere alle altre risposte, a parte alcuni motivi per ascoltarli:

    Una classe astratta con solo i metodi astratti è essenzialmente un’interfaccia. La differenza è che potrebbe hanno una qualche forma di virtual attuazione, e qui sta la trappola: la sua troppo facile quando si cerca di ridurre la duplicazione utilizzando una classe di base per nascondere dipendenze.

    Supponiamo di avere un insieme di oggetti che bisogno a persistere tra le esecuzioni. Si è tentati di aggiungere una funzionalità di salvataggio per la classe base in modo che nessun altro ha da preoccuparsi di come il salvataggio funziona. Il problema è, se è totalmente nasconderlo, è possibile creare un test di incubo in cui attuazione deve essere testato, o altrimenti un sacco di funzionalità è relegato al solo test di integrazione. Utilizzando la Strategia per la funzionalità di salvataggio sarebbe assolutamente risolvere il problema, e i due possono essere combinati in modo abbastanza semplice.

    Il problema è più tentazione di un semplice stare male. L’ereditarietà non interrompere DI, ma non consiglia di esso. Se stai cercando di ottenere in SOLIDO e DI, si può essere meglio evitare eredità per ora.

Lascia un commento