This is a follow-up question to the answer given by @Peter Meyer given in this question (What does it mean to "program to an interface"?).
First, let me begin by saying I am loath to make this a new question. But (I love stackoverflow but I must be a little critical here) 1) I could not privately message Peter Meyer (read: https://meta.stackexchange.com/questions/93896/a-proposal-for-private-messaging-within-the-stack-exchange-network), 2) I could not post a 'follow-up' question (read: https://meta.stackexchange.com/questions/10243/asking-a-follow-up-question) and 3), the question was locked to avoid "explosion pills" and, alas, I do not have enough reputation to ask there.
So, I must post a new question.
In that thread, Peter Meyer showed a brilliant and funny example of when to use interfaces and why programming to interfaces is important.
My question is this: wouldn't using a wrapper class be another approach to solving his problem?
Couldn't you write:
interface IPest {
void BeAnnoying();
}
class HouseFly inherits Insect implements IPest {
void FlyAroundYourHead();
void LandOnThings();
void BeAnnoying() {
FlyAroundYourHead();
LandOnThings();
}
}
class Telemarketer inherits Person implements IPest {
void CallDuringDinner();
void ContinueTalkingWhenYouSayNo();
void BeAnnoying() {
CallDuringDinner();
ContinueTalkingWhenYouSayNo();
}
}
class DiningRoom {
DiningRoom(Person[] diningPeople, IPest[] pests) { ... }
void ServeDinner() {
when diningPeople are eating,
foreach pest in pests
pest.BeAnnoying();
}
}
in this way:
class IPest {
HouseFly houseFly;
public IPest(HouseFly houseFly) {
this.houseFly = houseFly;
}
Telemarketer telemarketer;
public IPest(Telemarketer telemarketer) {
this.telemarketer = telemarketer;
}
void BeAnnoying() {
if(houseFly != null)
houseFly.BeAnnoying();
else
telemarketer.BeAnnoying();
}
}
class HouseFly inherits Insect {
void FlyAroundYourHead();
void LandOnThings();
void BeAnnoying() {
FlyAroundYourHead();
LandOnThings();
}
}
class Telemarketer inherits Person {
void CallDuringDinner();
void ContinueTalkingWhenYouSayNo();
void BeAnnoying() {
CallDuringDinner();
ContinueTalkingWhenYouSayNo();
}
}
class DiningRoom {
DiningRoom(Person[] diningPeople, IPest[] pests) { ... }
void ServeDinner() {
when diningPeople are eating,
foreach pest in pests
pest.BeAnnoying();
}
}
?
Although I tagged this as language-agnostic, I'm really "Java-ifying" this question because that is what I'm most familiar with, so please forgive me. But as I see it, there is disadvantage to using the interface approach. For instance, if you want to override the "toString()" method for the different types, to return a different value based on whether it's being represented as an "IPest" or a "HouseFly," with the interface you cannot do that. You can't give a different toString value for "HouseFly" by itself than you would for a HouseFly implementing the IPest interface with the interface (because HouseFly will always implement the interface by the class definition). A wrapper class would give you broader functionality than the interface would.
To illustrate: Let's say you wanted to display all of the "IPests" in a list, but you wanted the list to have a distinguishing mark on each one to display whether the pest was a Fly or a Telemarketer. Then with the wrapper class, this would be easy:
class IPest {
HouseFly houseFly;
public IPest(HouseFly houseFly) {
this.houseFly = houseFly;
}
Telemarketer telemarketer;
public IPest(Telemarketer telemarketer) {
this.telemarketer = telemarketer;
}
void BeAnnoying() {
if(houseFly != null)
houseFly.BeAnnoying();
else
telemarketer.BeAnnoying();
}
public String toString() {
return (houseFly == null? "(T) " + telemarketer.toString() : "(F) " + houseFly.toString()) +
}
}
Then, in another place, if you had a list to represent the HouseFly by itself (not as an IPest but as a HouseFly) then you could give a different value for toString().
This isn't limited to toString(), but any other method that those classes may have that you might want to override to provide different functionality when the object is being represented as a IPest vs when it is being represented as a HouseFly or Telemarketer.
I hope my question makes sense.
My theory is that: if you are programming an API or anything that anyone will use, you should avoid concrete classes and try to use interfaces. But if you are writing client code directly and have zero expectation (or possibility) of code reuse then "programming to interface" seems like a not-so-big-deal.
I'm looking forward to any feedback. Am I way off-base here? Am I terrible at writing code? Hopefully Peter Meyer will give his input...