Se stai utilizzando un linguaggio in cui le classi devono essere codificate nel codice (ad es. Java / C #), allora potrebbe essere logico utilizzare un'interfaccia nel caso tu voglia modificare l'implementazione di Behavior
che viene passato a ClientA
o ClientB
senza ricompilare. Questo di solito accade quando si desidera testare il codice unitario fornendo implementazioni fittizie di Behavior
. Senza un'interfaccia, dovresti modificare la dichiarazione di importazione del codice client in modo che faccia riferimento alla corretta implementazione e ricompilila.
Nelle lingue che non fanno riferimento al codice sorgente in classi che utilizzano identificatori univoci globali (che sono i nomi completi come com.yoursite.Foo) non è un problema e non è necessario creare un interfaccia. Tuttavia, le lingue con questo tipo di sistema di moduli sono linguaggi funzionali relativamente impopolari (ad esempio Standard ML, OCaml) quindi probabilmente non si applicano a te.
Si noti, tuttavia, che non tutte le classi possono essere implementate come un'interfaccia. Prendere in considerazione:
public class LooksAtOthers {
public LooksAtOthers binaryOperation(LooksAtOthers other) {
...
}
}
L'operazione binaria qui esamina i campi privati di other
. Questo risulta molto quando si implementano strutture dati; per fare fusioni o unioni efficienti devi essere in grado di guardare all'implementazione di entrambi gli operandi. Questo non può essere fatto da un'interfaccia:
public interface CantLook {
CantLook binaryOperation(CantLook other)
}
public class CantLookImpl implements CantLook {
public CantLook binaryOperation(CantLook other) {
// no idea what type CantLook has
}
}
Qui CantLook
è un'interfaccia, quindi la classe che implementa CantLook non ha idea di cosa siano i campi privati other
. Di conseguenza se binaryOperation
ha richiesto di guardare all'interno di other
, non può più essere implementato in modo efficiente.
Si noti inoltre che l'uso di una classe rende il debug un po 'più semplice. Con una classe ogni dato codice cliente interagisce solo con una implementazione; funziona o no. Con un'interfaccia ci può essere un numero qualsiasi di implementazioni e nulla impedisce a qualcuno di crearne uno cattivo. Se utilizzi un'interfaccia e ClientA
interruzioni, devi considerare quale implementazione di Behavior
l'ha interrotta. Qualcuno potrebbe averlo creato e passato in un buggy ImplementerC
.
Quindi la linea di fondo è: dipende. Ti dà fastidio dover cambiare le istruzioni di importazione? Stai facendo test unitari? Hai bisogno di guardare ad altre istanze della classe?