Ridurre il boilerplate in classe che implementa le interfacce attraverso la composizione

10

Ho una classe: A che è un composto di un numero di classi più piccole, B , C e D .

B , C e D implementano le interfacce IB , IC e ID rispettivamente.

Poiché A supporta tutte le funzionalità di B , C e D , A implementa IB , IC e ID , ma sfortunatamente questo porta a molto reinstradamento nell'implementazione di A

Così:

interface IB
{
    int Foo {get;}
}

public class B : IB
{
    public int Foo {get {return 5;}}
}

interface IC
{
    void Bar();
}

public class C : IC
{
    public void Bar()
    {
    }
}

interface ID
{
    string Bash{get; set;}
}

public class D: ID
{
    public string Bash {get;set;}
}

class A : IB, IC, ID
{
    private B b = new B();
    private C c = new C();
    private D d = new D();

    public int Foo {get {return b.Foo}}

    public A(string bash)
    {
        Bash = bash;
    }

    public void Bar()
    {
        c.Bar();
    }

    public string Bash
    {
         get {return d.Bash;}
         set {d.Bash = value;}
    }
}

C'è un modo per sbarazzarsi di qualsiasi reindirizzamento di questo boilerplate in A ? B , C e D implementano tutte funzionalità diverse ma comuni, e mi piace che A implementa IB , IC e ID perché significa che posso passare in A se stesso come dipendenza che corrisponde a quelle interfacce e non è necessario esporre i metodi interni di supporto.

    
posta Nick Udell 28.06.2015 - 02:52
fonte

4 risposte

7

Quello che stai cercando è comunemente chiamato mixins . Purtroppo, C # non supporta nativamente quelli.

Ci sono alcune soluzioni alternative: one , due , tre e molti altri.

In realtà mi piace davvero l'ultimo. L'idea di utilizzare automaticamente la classe parziale generata per generare il boilerplate è probabilmente la cosa più vicina a una soluzione davvero buona:

[pMixins] is a Visual Studio plug-in that scans a solution for partial classes decorated with pMixin attributes. By marking your class partial, [pMixins] can create a code-behind file and add additional members to your class

    
risposta data 29.06.2015 - 08:19
fonte
1

La tua classe sta facendo troppo, ecco perché devi implementare così tanto codice. Dici nei commenti:

it feels more sensible to write Person.Walk() as opposed to Person.WalkHelper.Walk()

Non sono d'accordo. È probabile che l'atto del camminare coinvolga molte regole e non appartenga alla classe Person - appartiene a una classe WalkingService con un metodo walk(IWalkable) in cui Persona implementa IWalkable .

Tieni sempre a mente i principi SOLID quando scrivi il codice. I due che sono più applicabili qui sono Separation of Concerns (estrae il codice walking in una classe separata) e Interface Segregation (divide le interfacce in compiti / funzioni / abilità specifici). Sembra che tu possa avere parte della I con le tue interfacce multiple, ma poi stai annullando tutto il tuo lavoro facendo in modo che una classe le implementasse.

    
risposta data 28.06.2015 - 19:19
fonte
1

Sebbene non riduca lo standard di codice nel codice stesso, Visual Studio 2015 ora dispone di un'opzione di refactoring per generare automaticamente lo standard per voi.

Per usarlo, prima crea la tua interfaccia IExample e implementazione Example . Quindi crea la tua nuova classe Composite e falla ereditare IExample , ma non implementare l'interfaccia.

Aggiungi una proprietà o un campo di tipo Example alla tua classe Composite , apri il menu delle azioni rapide sul token IExample nel tuo file di classe Composite e seleziona "Implementa l'interfaccia con" Esempio "" dove "Esempio" in questo caso è il nome del campo o della proprietà.

Si noti che, mentre Visual Studio genererà e reindirizzerà tutti i metodi e le proprietà definiti nell'interfaccia per questa classe helper, sarà non reindirizzare gli eventi al momento della pubblicazione della risposta.

    
risposta data 03.07.2015 - 13:36
fonte
-1

Quello che stai cercando è l'ereditarietà multipla. Tuttavia, né C # né Java ce l'hanno.

È possibile estendere B da A. Ciò eliminerà la necessità di un campo privato per B e della colla di reindirizzamento. Ma puoi farlo solo con uno di B, C o D.

Ora se puoi fare C ereditare da B e D da C devi solo avere A esteso D ...;) - per essere chiari però, in realtà non sto incoraggiando che in questo esempio non c'è indicazione per questo.

In C ++ saresti in grado di ereditare A da B, C e D.

Ma l'ereditarietà multipla rende i programmi più difficili da ragionare e ha i suoi problemi; Inoltre, c'è spesso un modo pulito per evitarlo. Tuttavia, a volte senza di esso, è necessario creare compromessi di progettazione tra il boilerplate ricorrente e il modo in cui il modello dell'oggetto viene esposto.

Sembra un po 'come se stessimo cercando di mischiare composizione ed eredità. Se questo fosse C ++, potresti usare una soluzione di ereditarietà pura. Ma dato che non lo consiglierei, abbraccerei la composizione.

    
risposta data 28.06.2015 - 19:46
fonte