2010-07-15 5 views
9

È necessario creare sovraccarichi per le funzioni su un'interfaccia esistente senza influire sui componenti che attualmente implementano o utilizzano l'interfaccia (idealmente).Aggiunta di nuove funzioni a un'interfaccia

Immagino ho un paio di opzioni:

semplificato interfaccia originale:

public interface IServerComponent 
{ 
    bool Add(int a, int b); 
} 

posso aggiungere le nuove funzioni sovraccaricate per l'interfaccia e forzare ogni classe che implementa l'interfaccia per implementare le nuove funzioni.

public interface IServerComponent 
{ 
    bool Add(int a, int b); 
    bool Add(int a, int b, int c); 
} 

Oppure posso creare una nuova interfaccia che implementa l'interfaccia originale. Poi altre classi che fanno uso della originale non avranno bisogno di cambiare e di eventuali nuove classi possono implementare la nuova interfaccia ...

public interface IServerComponent2 : IServerComponent 
{ 
    bool Add(int a, int b, int c); 
} 

Qual è la migliore pratica è questa situazione? Ci sono altre opzioni disponibili?

Grazie

risposta

11

Se i nuovi metodi possono essere espresse in termini di vecchi metodi, è possibile utilizzare metodi di estensione:

// Original interface 
public interface IServerComponent 
{ 
    bool Add(int a, int b, int c); 
} 

// New overload 
public static class MyServerMethods 
{ 
    public static bool Add(this IServerComponent component, int a, int b) 
    { 
    return component.Add(a, b, 0); 
    } 
} 

Se i metodi non possono essere espresse in quel modo (cioè, davvero bisogno di essere implementato dai componenti stessi), quindi consiglierei di definire una nuova interfaccia. Questo approccio ha la massima compatibilità con le versioni precedenti.

+0

+1 Per menzionare metodi di estensione – ram

+1

metodi di estensione funzionerà, ma avrà anche l'effetto di diffusione della funzionalità della classe di esecuzione attraverso altre classi riducenti coesione. La vedo come una soluzione temporanea al meglio. Nel caso in cui non è possibile estendere la classe, poiché non si ha accesso alla fonte, i metodi di estensione hanno senso. Potrei farlo in questo modo per aggiornamenti minori di una base di codice esistente, ma certamente lo inserirò nella mia lista di refactoring per la prossima major release. – tvanfosson

+2

Questo dipende totalmente dal design. Se aggiungete * nuove funzionalità *, sarei d'accordo; appartiene a un'interfaccia. Se stai aggiungendo * overload * (ad esempio, funzionalità quasi identiche, sempre espresse in termini di altre funzionalità), non sono d'accordo. In questo caso, i metodi di estensione consentono * l'ortogonalità *, riducendo la duplicazione del codice. [Joe Duffy] (http://www.bluebytesoftware.com/blog/2010/02/10/ExtensionMethodsAsDefaultInterfaceMethodImplementations.aspx) ha un buon post sul blog sull'argomento. –

4

Se l'interfaccia IServerComponent non è ancora stata spedita o è un'interfaccia interna implementata solo dalle proprie classi e i nuovi membri dell'interfaccia hanno senso per tutte le classi esistenti che implementano l'interfaccia, modificare l'interfaccia esistente.

In caso contrario, creare un'interfaccia IServerComponent2 che estenda IServerComponent. IIRC è ciò che raccomandano le linee guida di progettazione. Un esempio di questo può essere trovato in .NET Framework in forma della classe X509Certificate2.

Tuttavia, se i nuovi membri possono essere implementate in termini di membri originali, si potrebbe anche usare extension methods:

public interface IServerComponent 
{ 
    bool Add(int a, int b); 
} 

public static class ServerComponentExtensions 
{ 
    public static bool Add(this IServerComponent isc, int a, int b, int c) 
    { 
     return isc.Add(a, b) && isc.Add(b, c) && isc.Add(c, a); 
    } 
} 
0

Dipende dal contesto - se ci sono molte classi che implementano l'interfaccia originale, o se è pubblicato, l'unico modo pratico è di introdurre quello nuovo. D'altra parte avere una sola interfaccia è molto più pulita a lungo termine, quindi direi refactoring quello esistente se te lo puoi permettere.

0

Se non è necessario o si desidera modificare le classi (ora o in futuro) che già implementano la vecchia interfaccia, è sufficiente creare una seconda interfaccia. Tuttavia, sembra più un trucco e potrebbe darti un codice meno intuitivo.

Inoltre, posticipare un refactoring non è mai una buona idea nella mia esperienza. Quindi se sospetti di dover implementare l'interfaccia in un secondo momento, potresti anche modificare quello esistente e risparmiarti un po 'di mal di testa. È sicuramente il modo più pulito per farlo.

0

penso che il mantenimento di una singola interfaccia è più semplice, ma il secondo approccio con 2 interfaccia è meglio perché non ogni classe deve implementare bool Add(int a, int b, int c);

1

Mi rendo conto che il vostro esempio è forzato ma voglio dare una risposta artificioso che è diverso da quello che stai esprimendo in modo che tu possa pensarci in un modo diverso. Invece di far funzionare il metodo dell'interfaccia su qualcosa di concreto, potrebbe avere senso lavorare su qualcosa di astratto.

Per esempio

public interface IAddableThings 
{ 
    int a; 
    int b; 
} 

public interface IOtherAddableThings : IAddableThings 
{ 
    int a; 
    int b; 
} 

public interface IServerComponent 
{ 
    bool Add(IAddableThings things); 
} 

Se questo è davvero un componente aggiuntivo, allora penso che questo rende molto più senso, ma se è davvero più come Calcolare(), si sarebbe poi desidera spostare alcuni o tutti quell'operazione di metodi fino agli oggetti IAddableThings.

public interface IAddableThings 
{ 
    int a; 
    int b; 
    bool CalculateMe(); 
}