Ho bisogno di una classe genitore se sto usando un'interfaccia?

3

Sto iniziando a lavorare a un nuovo progetto personale per inviare e-mail utilizzando diversi servizi di posta elettronica (come mailchimp, ad esempio). Ho appena iniziato a scrivere codice e ho una classe base chiamata Email:

public class Email
{
    private string _to;
    private string _from;
    private string _body;
    private string _templateName;

    public Email(string to, string from, string body, string templateName)
    {
        this._to = to;
        this._from = from;
        this._body = body;
        this._templateName = templateName;
    }
}

un'interfaccia chiamata IEmail:

public interface IEmail
{     
    string Send();
}

e una classe chiamata MailChimpEmail che invierà email usando l'API MailChimps e che eredita da Email e implementa l'interfaccia di IEmail

public class MailChimpEmail : Email, IEmail
{
    private string _body;
    private string _to;
    private string _from;
    private string _templateName;

    public MailChimpEmail (string to, string from, string body, string templateName) : base(to, from, body, templateName)
    {
        this._to = to;
        this._from = from;
        this._body = body;
        this._templateName = templateName;
    }

    public string Send()
    {            
        throw new NotImplementedException();
    }
}

Ho intenzione di utilizzare un altro mittente e-mail di terze parti, quindi non sono legato a uno e creerò una nuova classe e implementerò l'interfaccia di IEmail e erediterò l'e-mail. Ma la mia domanda è: devo davvero ereditare l'email? Supponiamo che le classi non acquisiscano alcuna nuova funzionalità e rimangano tali (quindi posso semplicemente inviare una e-mail, è così), che cosa sto guadagnando ereditando la classe base se sto implementando l'interfaccia? Il metodo Send avrà un'implementazione diversa per ogni classe, quindi quale sarebbe il punto?

    
posta ygetarts 18.11.2015 - 00:01
fonte

3 risposte

5

Un'interfaccia e una classe genitore (o base) risolvono problemi diversi, quindi dipende dal problema che stai cercando di risolvere.

Un'interfaccia definisce un contratto. Questo è utile quando si desidera manipolare una varietà di implementazioni concrete in modo coerente e ben definito. Sono ottimi per nascondere i dettagli cruenti che probabilmente non contano nel consumatore. Sono anche bravi a costringerci a pensare a astrazioni utili.

Una classe base offre anche un tipo di contratto (qualsiasi numero di classi estese può essere gestito come se fosse la classe base), ma la sua caratteristica più utile è la sua implementazione concreta e condivisa. Se hai un'implementazione identica in una famiglia di classi correlate, puoi ASCIUGARE il tuo codice con una classe base.

A prima vista, sembra che il tuo esempio richieda solo l'interfaccia. Non c'è un'evidente implementazione condivisa. Guardando più vicino, però, mi chiedo. Sia Email che MailChimpEmail definiscono un corpo, indirizzi e un modello. Potrebbe valere la pena di definirli una sola volta, soprattutto se c'è una gestione difficile dello stato. Se ogni tipo di email deve definire il proprio Send (), una classe base astratta potrebbe meglio trasmettere l'intento (la classe base non è in grado di istanziare). Ottieni un piccolo contratto e una piccola implementazione concreta.

public abstract class BaseEmail
{
    public string Body { get; set; }
    public string From { get; set; }
    public string To { get; set; }
    public string Template {get; set; }

    protected BaseEmail (string body, string from, string to, string template)
    {
        this.Body = body;
        this.From = from;
        this.To = to;
        this.Template = template;
    }

    public abstract string Send();
}

public class VanillaEmail : BaseEmail
{
    public VanillaEmail (string body, string from, string to, string template)
        : base (body, from, to, template)
    {
    }

    public override string Send()
    {
        // do some vanilla work
    }
}

public class MailChimpEmail : BaseEmail
{
    public MailChimpEmail (string body, string from, string to, string template)
        : base (body, from, to, template)
    {
    }

    public override string Send()
    {
        // do some mailchimp work
    }
}

Ricorda che questo è solo un modo per modellare il problema. Alcuni sostengono che un'e-mail non dovrebbe essere in grado di inviare se stessa. In questo caso, puoi separare la preoccupazione di inviare un messaggio e-mail dal messaggio stesso.

public class Email
{
    public string Body { get; set; }
    public string From { get; set; }
    public string To { get; set; }
    public string Template {get; set; }
}

public interface IMailer
{
    string Send(Email email);
}

public class VanillaMailer : IMailer
{
    public string Send(Email email)
    {
        // do some vanilla work
    }
}

public class MailChimpMailer : IMailer
{
    public string Send(Email email)
    {
        // do some mailchimp work
    }
}
    
risposta data 18.11.2015 - 06:17
fonte
1

Dovremmo ereditare se esiste un 'è una relazione'. Dovremmo usare l'aggregazione se c'è un 'ha una relazione'.

Non è necessario ereditare la classe 'Email' in ogni email che invia classi di implementazione. La tua classe 'Email' è una classe modello. Le email che inviano le classi di implementazione logica dovrebbero implementare l'interfaccia "IEmail" e utilizzare al loro interno la variabile privata "Email".

public class Email
{
    private string _to;
    private string _from;
    private string _body;
    private string _templateName;

    public Email(string to, string from, string body, string templateName)
    {
        this._to = to;
        this._from = from;
        this._body = body;
        this._templateName = templateName;
    }
}

public interface IEmail
{
    string Send();
}

public class MailChimpEmail : IEmail
{
    private Email _email;

    public MailChimpEmail(Email email)
    {
        this._email = email;
    }

    public string Send()
    {
        // implementation goes here...
    }
}

public class ThirdPartyEmail : IEmail
{
    private Email _email;

    public ThirdPartyEmail(Email email)
    {
        this._email = email;
    }

    public string Send()
    {
        // Third party implementation goes here...
    }
}

'MailChimpEmail' e 'ThirdPartyEmail' implementano l'interfaccia 'IEmail' e danno la propria logica al metodo 'send ()'. 'MailChimpEmail' e 'ThirdPartyEmail' sono in 'ha una relazione' con la classe 'Email', quindi non dovrebbe ereditare piuttosto dovrebbe usare la variabile di tipo 'Email' al loro interno con cui lavorare (questa è chiamata aggregazione).

    
risposta data 18.11.2015 - 04:22
fonte
0

Hai ragione, non stai guadagnando nulla ereditando l'Email. In effetti, l'e-mail di classe adesso è completamente inutile. Usare solo interface va bene. Se lo desideri, puoi utilizzare un abstract class anziché un interface , ma lo faranno entrambi.

    
risposta data 18.11.2015 - 01:41
fonte

Leggi altre domande sui tag