ISP basically says that it's not good to require from a class to implement unrelated things, and/or make a client require unrelated things. Methods in an interface are related — a client may need all of them to complete some reasonable task.
I think getInternalID
and getExternalID
belong to separate interfaces, since clients wanting one of these don't need the other, per your words.
The class that currently implements InternalEntityIdTransformer
could happily implement one more interface, say, ExternalEntityIdTransformer
, if sharing of implementation details saves you some work. If at some moment you would need to split the implementations (e.g. external to internal is trivial, but the reverse requires heavy lifting), it will be painless, as it should be.
Both are correct
The way I read it, the purpose of ISP (Interface Segregation Principle) is to keep interfaces small and focused: all interface members should have very high cohesion. Both definitions are intended to avoid "jack-of-all-trades-master-of-none" interfaces.
Interface segregation and SRP (Single Responsibility Principle) have the same goal: ensuring small, highly cohesive software components. They complement each other. Interface segregation ensures that interfaces are small, focused and highly cohesive. Following the single responsibility principle ensures that classes are small, focused and highly cohesive.
The first definition you mention focuses on implementers, the second on clients. Which, contrary to @user61852, I take to be the users/callers of the interface, not the implementers.
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.
To me the second definition, with the clients as the callers of the interface, is a better way of getting to the intended goal.
Segregating
In your question you state:
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(), B() and C():
But that is turning the world upside down.
- A class implementing an interface does not dictate what it needs in the interface it is implementing.
- The interfaces dictate what methods an implementing class should provide.
- The callers of an interface really are the ones that dictate what functionality they need the interface to provide for them and thus what an implementer should provide.
So when you are going to split IFat
into smaller interface, which methods end up in which ISmall
interface should be decided based on how cohesive the members are.
Consider this interface:
interface IEverythingButTheKitchenSink
{
void DoDishes();
void CleanSink();
void CutGreens();
void GrillMeat();
}
Which methods would you put in ICook
and why? Would you put CleanSink
together with GrillMeat
just because you happen to have a class that does just that and a couple of other things but nothing like any of the other methods? Or would you split it into two more cohesive interfaces, such as:
interface IClean
{
void DoDishes();
void CleanSink();
}
interface ICook
{
void CutGreens();
void GrillMeat();
}
Interface declaration note
An interface definition should preferably be on its own in a separate unit, but if it absolutely needs to live with either caller or implementer, it should really be with the caller. Otherwise the caller gets an immediate dependency on the implementer which is defeating the purpose of interfaces altogether. See also: Declaring interface in the same file as the base class, is it a good practice? on Programmers and Why should we place interfaces with classes that use them rather than those that implement them? on StackOverflow.
Best Answer
I like to interpret Interface Segregation Principle as
This implies that for each interface, there is always code that uses this interface. This is not the case of
IConvertible
. The interface itself doesn't make much sense. I also never saw property or function that was typedIConvertible
, which empowers my claims. I even wonder how would code that only works onIConvertible
looks and what would it do.