When you need a part of the class to be implemented. The best example I've used is the template method pattern.
public abstract class SomethingDoer
{
public void Do()
{
this.DoThis();
this.DoThat();
}
protected abstract void DoThis();
protected abstract void DoThat();
}
Thus, you can define the steps that will be taken when Do() is called, without knowing the specifics of how they will be implemented. Deriving classes must implement the abstract methods, but not the Do() method.
Extensions methods don't necessarily satisfy the "must be a part of the class" part of the equation. Additionally, iirc, extension methods cannot (appear to) be anything but public in scope.
edit
The question is more interesting than I had originally given credit for. Upon further examination, Jon Skeet answered a question like this on SO in favour of using interfaces + extension methods. Also, a potential downside is using reflection against an object hierarchy designed in this way.
Personally, I am having trouble seeing the benefit of altering a currently common practice, but also see few to no downsides in doing it.
It should be noted that it is possible to program this way in many languages via Utility classes. Extensions just provide the syntactic sugar to make the methods look like they belong to the class.
First, lets understand what was the issue:
The Staple job knows about many more methods which it doesn't use today, (e.g., the print
method) but which are available for it to use, should it want to.
However, the Job class "thinks" that the Staple class will be "a good citizen" and never use the print method at all.
There are many potential big issues here -
For some reason, the Staple job may start using the print method - by accident or intentionally.
Then down the road, either any changes to the print method may go untested,
OR, any changes to the print method will trigger a regression test in the Staple job also,
AND, any impact analysis for changes to the print job will necessarily involve impact analysis of the staple job too.
This is just the issue of Staple knowing about the print functions. Then there's the case of the Print job knowing all about stapling functions. Same problems.
Very soon, this system would reach a point where any change will require a full blown impact analysis of each module and a full blown regression test.
Another problem is that today, all jobs which can be printed can be stapled, and vice versa on this particular printer.
However, tomorrow, there could be a need to install the same firmware on a device that only prints or only staples. What then? The code already assumes that all Jobs are printable and stapleable. So any further granular breakdown / simplification of responsibilities is impossible.
In more recent terms, imagine a class called "AppleDevice" which has functions for MakePhoneCall as well as PlayMusic. Now your problem is while you can easily use this on an iPhone, you cannot use it for an iPod since the iPod cannot make phone calls.
So, the issue is not that the Job class is all-powerful. In fact, that's how it should be, so that it can act as a common link in the entire "workflow" where someone may scan a job, then print it, then staple it etc.
The problem is that the usage of all its methods is not restricted. Anyone and everyone could use and abuse any method whenever they want to, thus making the maintenance difficult.
Hence, the Dependency Injection approach of only telling users "exactly what they need to know, and nothing more" ensures that calling modules only use the code that they are meant to.
A sample implementation would look like:
interface IStapleableJob { void stapleYourself(); }
interface IPrintableJob { void printYourself(); }
class Job implements IStapleableJob, IPrintableJob {
....
}
class Staple {
public static void stapleAllJobs(ArrayList<IStapleableJob> jobs) {
for(IStapleableJob job : jobs) job.stapleYourself();
}
}
class Print {
public static void stapleAllJobs(ArrayList<IPrintableJob> jobs) {
for(IPrintableJob job : jobs) job.printYourself();
}
}
Here, even if you pass a Job object to the Staple and Print methods, they dont know that its a Job, so they cannot use any methods that they are not supposed to. Thus, when you make any changes to a module, your scope of impact analysis and regression testing is restricted. That's the problem that ISP solves.
Best Answer
The consumer of dependencies is the one responsible for defining them (by means of their interfaces). In your example,
BarDataMapper
rules. I see two possible scenarios:If
BarDataMapper
depends on a single object implementing bothprepare()
andquery()
methods, then yes, a properPreparableAndQueryable
interface should be defined including the two of them, and passed to the constructor. But then, perhaps you want to find another meaningful, non-composed name not hinting at bad separation of concerns.If it makes sense for
BarDataMapper
to consume independentPreparable
andQueryable
dependencies, then its constructor takes them as separate parameters, even if in the end there's really one single object implementing both interfaces. Who's really implementing interfaces should not bother the one consuming them.