这是@Peter Meyer 在这个问题中给出的答案的后续问题(“编程到接口”是什么意思?)。
首先,让我先说我不愿意提出这个新问题。但是(我喜欢stackoverflow,但我必须在这里有点挑剔)1)我不能私信Peter Meyer(阅读:https ://meta.stackexchange.com/questions/93896/a-proposal-for-private-messaging- inside-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-ifying”这个问题,因为这是我最熟悉的,所以请原谅我。但正如我所见,使用接口方法有缺点。例如,如果你想覆盖不同类型的“toString()”方法,根据接口是表示为“IPest”还是“HouseFly”返回不同的值,你不能这样做。您不能单独为“HouseFly”提供与使用接口实现 IPest 接口的 HouseFly 不同的 toString 值(因为 HouseFly 将始终通过类定义实现接口)。包装类会为您提供比接口更广泛的功能。
举例说明:假设您想在一个列表中显示所有“IPests”,但您希望该列表在每个列表上都有一个区别标记,以显示害虫是苍蝇还是电话推销员。然后使用包装类,这很容易:
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 或任何任何人都会使用的东西,您应该避免使用具体的类并尝试使用接口。但是,如果您直接编写客户端代码并且对代码重用的期望(或可能性)为零,那么“编程到接口”似乎不是什么大问题。
我期待任何反馈。我在这里离基地很远吗?我写代码很糟糕吗?希望彼得迈耶能提供他的意见......