Quando si leggono articoli su ISP, sembrano esserci due definizioni contraddittorie di ISP:
Secondo la prima definizione (vedi 1 , 2 , 3 ), l'ISP afferma che le classi che implementano l'interfaccia non dovrebbero essere costrette a implementare funzionalità di cui non hanno bisogno. Quindi, interfaccia fatIFat
interface IFat
{
void A();
void B();
void C();
void D();
}
class MyClass: IFat
{ ... }
dovrebbe essere suddiviso in interfacce più piccole ISmall_1
eISmall_2
interface ISmall_1
{
void A();
void B();
}
interface ISmall_2
{
void C();
void D();
}
class MyClass:ISmall_2
{ ... }
poiché in questo modo my MyClass
è in grado di implementare solo i metodi di cui ha bisogno ( D()
e C()
), senza essere costretto a fornire anche implementazioni fittizie per A()
, B()
e C()
:
Ma secondo la seconda definizione (vedi 1 , 2 , risposta di Nazar Merza ), l'ISP afferma che MyClient
chiamare i metodi su MyService
non dovrebbe essere consapevole dei metodi su MyService
cui non ha bisogno. In altre parole, se MyClient
solo ha bisogno della funzionalità di C()
e D()
, quindi invece di
class MyService
{
public void A();
public void B();
public void C();
public void D();
}
/*client code*/
MyService service = ...;
service.C();
service.D();
dovremmo separare i MyService's
metodi in interfacce specifiche del cliente :
public interface ISmall_1
{
void A();
void B();
}
public interface ISmall_2
{
void C();
void D();
}
class MyService:ISmall_1, ISmall_2
{ ... }
/*client code*/
ISmall_2 service = ...;
service.C();
service.D();
Pertanto, con la prima definizione, l'obiettivo dell'ISP è " semplificare la vita delle classi che implementano l'interfaccia IFat ", mentre con quest'ultima l'obiettivo dell'ISP è " semplificare la vita dei clienti che chiamano i metodi di MyService ".
Quale delle due diverse definizioni di ISP è effettivamente corretta?
@MARJAN VENEMA
1.
Quindi, quando hai intenzione di dividere IFat in un'interfaccia più piccola, quali metodi finiscono in cui ISmallinterface dovrebbe essere deciso in base alla coesione dei membri.
Mentre ha senso mettere metodi coerenti all'interno della stessa interfaccia, ho pensato che con il modello ISP le esigenze del cliente abbiano la precedenza sulla "coesione" di un'interfaccia. In altre parole, ho pensato che con l'ISP dovremmo raggruppare all'interno della stessa interfaccia quei metodi richiesti da determinati clienti, anche se ciò significa lasciare fuori da quella interfaccia quei metodi che dovrebbero, per motivi di coesione, essere inseriti all'interno di quella stessa interfaccia?
Così, se c'erano un sacco di clienti che saranno sempre e solo bisogno di chiamare CutGreens
, ma non anche GrillMeat
, poi per aderire al modello ISP dobbiamo solo mettere CutGreens
dentro ICook
, ma non anche GrillMeat
, anche se i due metodi sono altamente coesivo ?!
2.
Penso che la tua confusione derivi da un presupposto nascosto nella prima definizione: che le classi attuatrici stanno già seguendo il principio della responsabilità unica.
"Implementando classi che non seguono SRP" ti riferisci a quelle classi che implementano IFat
o alle classi che implementano ISmall_1
/ ISmall_2
? Presumo che ti riferisci alle classi che implementano IFat
? In tal caso, perché pensi che non seguano già SRP?
Grazie