これは、この質問で与えられた @Peter Meyer の回答に対するフォローアップの質問です ( What does it mean to "program to an interface"? )。
最初に、これを新しい質問にするのは嫌だということから始めさせてください。しかし(私はstackoverflowが大好きですが、ここでは少し批判的でなければなりません)1)私はPeter Meyerに個人的にメッセージを送ることができませんでした(読む: within-the-stack-exchange-network )、2) 「フォローアップ」の質問を投稿できませんでした (読み取り: https://meta.stackexchange.com/questions/10243/asking-a-follow-up-question)および3)、質問は「爆発の丸薬」を避けるためにロックされていましたが、残念ながら、そこで質問するのに十分な評判がありません。
そのため、新しい質問を投稿する必要があります。
そのスレッドで、Peter Meyer は、インターフェイスをいつ使用するか、インターフェイスへのプログラミングが重要である理由について、見事で面白い例を示しました。
私の質問はこれです.ラッパークラスを使用することは、彼の問題を解決するための別のアプローチではないでしょうか?
あなたは書くことができませんでした:
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();
}
}
この上:
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();
}
}
?
私はこれを言語にとらわれないものとしてタグ付けしましたが、私が最もよく知っているので、この質問を実際に「Java 化」しているので、ご容赦ください。しかし、私が見たように、インターフェイス アプローチを使用することには欠点があります。たとえば、さまざまなタイプの「toString()」メソッドをオーバーライドして、「IPest」または「HouseFly」として表されているかどうかに基づいて異なる値を返す場合、インターフェイスではそれを行うことはできません。「HouseFly」自体に、IPest インターフェースをインターフェースで実装する HouseFly の場合とは異なる toString 値を与えることはできません (HouseFly は常にクラス定義によってインターフェースを実装するため)。ラッパー クラスは、インターフェイスよりも幅広い機能を提供します。
例として、リスト内のすべての「IPest」を表示したいとしますが、害虫がハエなのかテレマーケティング担当者なのかを表示するために、リストのそれぞれに識別マークを付けたいとします。次に、ラッパー クラスを使用すると、これは簡単になります。
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()) +
}
}
次に、別の場所で、HouseFly を単独で (IPest ではなく HouseFly として) 表すリストがある場合は、toString() に別の値を指定できます。
これは toString() に限定されませんが、オブジェクトが IPest として表されている場合と、HouseFly または Telemarketer として表されている場合とで異なる機能を提供するためにオーバーライドしたい場合がある、これらのクラスの他のメソッドがあります。
私の質問が理にかなっていることを願っています。
私の理論では、API など、誰もが使用するものをプログラミングしている場合は、具体的なクラスを避け、インターフェイスを使用するようにしてください。しかし、クライアント コードを直接記述していて、コードの再利用の見込みがない (または可能性がない) 場合、「インターフェイスへのプログラミング」はそれほど大したことではないように思えます。
フィードバックをお待ちしております。私はここで基地外ですか?私はコードを書くのが苦手ですか? うまくいけば、Peter Meyer が意見を述べてくれます...