Utilizza l'interfaccia o la classe astratta?

4

Ora il titolo potrebbe sembrare che la domanda sia già stata fatta prima, ma lascia che ti spieghi la mia situazione e vedrai perché sto facendo questa domanda.

Consideriamo questa interfaccia:

public interface IListChangedListener {
    public event EventHandler ItemAdded;
    public event EventHandler ItemRemoved;
}

Se qualcuno vuole implementare questa interfaccia, dovrebbe controllare se ItemAdded è nullo e solo se non è nullo, lo chiamerebbero. Bene, voglio semplificare il loro lavoro dando una funzione integrata che farà lo stesso. Basta chiamare quella funzione per verificare se l'evento corrispondente è nullo e, in caso contrario, farà scoppiare il suo evento corrispondente.

Il problema è che questa è un'interfaccia. Quindi non posso definire un metodo. Così ho pensato di andare con una classe astratta. Ma considerando la situazione, sarebbe meglio adattarlo a un'interfaccia anziché a una classe astratta.

Quindi mi limito ad abbandonare l'idea di dare una funzione integrata? O ne faccio una classe astratta? Quale si adatta meglio alla situazione? Sto passando un momento difficile per decidere quale usare. Qualche aiuto per favore?

    
posta Rakshith Ravi 15.03.2015 - 17:26
fonte

3 risposte

2

Quale sarebbe meglio avere un mixin, ma sfortunatamente C # non include questo concetto. In assenza di mix, selezionerei un'interfaccia su una classe astratta quasi ogni volta, e sicuramente in questo caso. Qualunque funzionalità debba essere offerta alle classi derivate, può essere offerta sotto forma di oggetti helper e funzioni di utilità. Favorire la composizione sull'ereditarietà è il mio principio di progettazione preferito.

In questo caso specifico dovremmo essere in grado di averli entrambi però. Avrei sicuramente l'interfaccia, come l'hai definita. L'interfaccia dovrebbe essere utilizzata da tutti i consumatori e altre classi nella tua utilità. Per la comodità dei tuoi utenti (sviluppatori) avrei anche un'implementazione predefinita dell'interfaccia che può essere usata come una classe base.

public interface IListChangedListener {
    public event EventHandler ItemAdded;
    public event EventHandler ItemRemoved;
}

public class ListChangedListener : IListChangedListener {
    public event EventHandler ItemAdded;
    public event EventHandler ItemRemoved;

    public void FireItemAdded(...) {
        if (ItemAdded != null)
            ItemAdded(...)
    }

    public void FireItemRemoved(...) {
        if (ItemRemoved != null)
            ItemRemoved(...)
    }
}

In questo modo uno sviluppatore può derivare dalla classe ListChangedListener o implementare direttamente l'interfaccia IListChangedListener , a seconda delle circostanze. Alla fine della giornata ciò che conta è che la classe listener che forniscono implementa l'interfaccia IListChangedListener .

Funzionerebbe?

    
risposta data 17.03.2015 - 08:18
fonte
3

Come al solito:

  • Se è necessario implementare alcuni metodi, l'interfaccia non è una soluzione. Devi usare una classe astratta.

  • D'altra parte, se devi descrivere il comportamento, specialmente in un contesto in cui le classi che hanno questo comportamento potrebbero già avere una classe genitore, devi usare un'interfaccia, poiché in C #, una classe non può avere più genitori.

Se hai bisogno dei vantaggi di entrambi i mondi, non utilizzare né un'interfaccia, né una classe astratta, ma avere un oggetto separato utilizzato all'interno degli oggetti.

Nel tuo caso, devi descrivere il comportamento. La logica aziendale portata da un'eventuale classe astratta o da una classe dedicata non è così utile: è solo un assegno nulla, niente di più. Pertanto, la ripetizione di quei controlli nulli in classi diverse che implementano l'interfaccia non costituirebbe una grave violazione del principio di DRY.

D'accordo, la maggior parte degli implementatori finirà per creare due metodi che controllano la nullità e generano l'evento, ma, ancora una volta, non è così complicato da fare (e nemmeno la logica cambierà nel tempo).

Dai commenti, sembra che tu stia reinventando la ruota. In .NET Framework, esiste già una classe che fa ciò di cui hai bisogno: ObservableCollection<T> .

Non ha nulla a che fare con WPF: è una parte di System.Collections.ObjectModel namespace, quella che contiene molte cose relative alle collezioni, incluso Collection<T> stesso, ReadOnlyCollection<T> , ecc. Puoi usare quelle raccolte fuori da WPF , ovvero in un'applicazione console, un progetto Windows Form o un sito Web.

    
risposta data 15.03.2015 - 17:34
fonte
2

Dovresti avere sia l'interfaccia che una classe con un'implementazione predefinita. Ad esempio, se si dispone di un'interfaccia IDog, potrebbe essere definito un metodo Bark (). Una classe Voicebox separata potrebbe fornire l'implementazione predefinita. Questo potrebbe apparire come questo:

public interface IDog
{
    public void Bark();
}

public class VoiceBox
{
    public void Bark()
    {
        // Do bark
    }
}

class Poodle : IDog
{
    private Voicebox voicebox = Voicebox.GetDefault();

    public Bark()
    {
        voicebox.Bark();
    }
}

In questo modo, il client non è obbligato a usare la tua classe Voicebox, ma è comunque richiesto che il cane abbaia in qualche modo. Se desiderano utilizzare l'implementazione predefinita, possono utilizzare la classe Voicebox. Naturalmente, puoi rendere virtuale il metodo della corteccia nella classe Voicebox se deve essere sovrascritto dalle sottoclassi.

    
risposta data 16.03.2015 - 03:41
fonte

Leggi altre domande sui tag