When reading articles on ISP, there seem to be two contradicting definitions of ISP:
According to first definition ( see 1, 2, 3), ISP states that classes implementing the interface shouldn't be forced to implement functionalities which they don't need. Thus, fat interface IFat
interface IFat
{
void A();
void B();
void C();
void D();
}
class MyClass: IFat
{ ... }
should be split into smaller interfaces ISmall_1
and ISmall_2
interface ISmall_1
{
void A();
void B();
}
interface ISmall_2
{
void C();
void D();
}
class MyClass:ISmall_2
{ ... }
since this way my MyClass
is able to implement only the methods it needs ( D()
and C()
), without being forced to also provide dummy implementations for A()
and B()
:
But according to the second definition ( see 1 , 2, answer by Nazar Merza), ISP states that MyClient
calling methods on MyService
shouldn't be aware of methods on MyService
that it doesn't need. In other words, if MyClient
only needs the functionality of C()
and D()
, then instead of
class MyService
{
public void A();
public void B();
public void C();
public void D();
}
/*client code*/
MyService service = ...;
service.C();
service.D();
we should segregate MyService's
methods into client-specific interfaces:
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();
Thus with the former definition, the goal of ISP is to "make the life of classes implementing IFat interface easier", while with the latter the goal of ISP is to "make the life of clients calling methods of MyService easier".
Which of the two different definitions of ISP is actually correct?
@MARJAN VENEMA
1.
So when you are going to split IFat into smaller interface, which methods end up in which ISmallinterface should be decided based on how cohesive the members are.
While it makes sense to put cohesive methods within the same interface, I thought with ISP pattern the needs of the client take precedence over the "cohesiveness" of an interface. In other words, I thought with ISP we should lump within the same interface those methods needed by particular clients, even if that means leaving out of that interface those methods that should, for the sake of cohesiveness, also be put inside that same interface?
Thus, if there were lots of clients that will only ever needed to call CutGreens
, but not also GrillMeat
, then to adhere to ISP pattern we should only put CutGreens
inside ICook
, but not also GrillMeat
, even though the two methods are highly cohesive?!
2.
I think that your confusion stems from the a hidden assumption in the first definition: that the implementing classes are already following the single responsibility principle.
By "implementing classes not following SRP" are you referring to those classes that implement IFat
or to classes that implement ISmall_1
/ ISmall_2
? I assume you're referring to classes that implement IFat
? If so, why do you assume they don't already follow SRP?
thanks