- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是@Peter Meyer 在此问题 ( What does it mean to "program to an interface"? ) 中给出的答案的后续问题。
首先,让我先说我不愿意提出这个新问题。但是(我喜欢 stackoverflow,但我必须在这里有点挑剔)1)我不能私下给 Peter Meyer 发消息(阅读:https://meta.stackexchange.com/questions/93896/a-proposal-for-private-messaging-within-the-stack-exchange-network),2)我不能发布“后续”问题(阅读:https://meta.stackexchange.com/questions/10243/asking-a-follow-up-question) ) 和 3),问题被锁定以避免“爆炸药”,唉,我没有足够的声誉在那里问。
所以,我必须发布一个新问题。
在该线程中,Peter Meyer 展示了一个精彩而有趣的示例,说明何时使用接口(interface)以及为什么对接口(interface)进行编程很重要。
我的问题是:使用包装器类不是解决他问题的另一种方法吗?
你不能写:
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 化”这个问题,因为这是我最熟悉的,所以请原谅我。但正如我所见,使用接口(interface)方法有缺点。例如,如果您想覆盖不同类型的“toString()”方法,根据它是被表示为“IPest”还是“HouseFly”来返回不同的值,您不能使用接口(interface)这样做。您不能为“HouseFly”本身提供与使用接口(interface)实现 IPest 接口(interface)的 HouseFly 不同的 toString 值(因为 HouseFly 将始终通过类定义实现接口(interface))。包装类将为您提供比接口(interface)更广泛的功能。
举例说明:假设您想在列表中显示所有“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 时,您可能希望重写这些方法以提供不同的功能或电话推销员。
我希望我的问题是有道理的。
我的理论是:如果您正在编写 API 或任何任何人都会使用的东西,您应该避免使用具体类并尝试使用接口(interface)。但是,如果您直接编写客户端代码并且对代码重用的期望(或可能性)为零,那么“针对接口(interface)编程”似乎没什么大不了的。
我期待着任何反馈。我在这里离基地很远吗?我写代码很糟糕吗?希望 Peter Meyer 能提供他的意见...
最佳答案
对我来说,这使代码变得更加丑陋,但没有明显的好处。 (这读起来有点刺耳,这不是我的本意......实际问题+1)。
最大的缺点是您的 IPest 类(class)。随着您继续添加可能的害虫,这个类会变得越来越庞大,并且充满了未使用的变量和代码。如果你有 30 种不同的害虫,那么你的 IPest 类已经比你的例子有 2 种大 15 倍,并且有很多额外的代码来支持所有这些类。
更糟糕的是,此代码的绝大部分实际上与实例化对象无关。如果 IPest 应该代表一只 HouseFly,那么有几个实例变量(一个用于每个其他类型的 IPest)都是空的,还有大量未使用的代码。更糟糕的是,如果 IPest 的多个值不为空,会发生什么情况?它是什么? (电话推销员 BrundleFly!)
将其与纯接口(interface)进行比较,纯接口(interface)不会随着更多类的实现而变大(因为它不在乎。)
最后,我认为用两个(或更多)对象(例如 HouseFly 对象和 IPest 对象)表示单个概念性想法(例如一只苍蝇)通常没有用(或一个好主意)。 .and more objects 因为你想添加更多的功能。对于每个包装器,您添加另一个对象,这是另一个可能跟踪和更新的对象。
这并不是说在某些非常特殊的情况下,像这样的事情不是一个好主意......但由于我上面描述的原因,我在这里没有看到它。
关于oop - 跟进 Peter Meyer 的 "programming to an interface"回答,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16467224/
Meyers Singleton 是否适用于有动态库的场景? IE。一个定义单例的库,其他人使用它,每个都在自己的编译单元中? (我想这无关紧要,但具体架构是 OS X 上带有框架的应用程序) 我正在
我已经阅读了很多关于单例的文章,它们应该在什么时候使用,什么时候不应该使用,以及如何安全地实现它们。我正在用 C++11 编写,并且遇到了 Meyer 的单例延迟初始化实现,如 this questi
是否可以使用参数定义 Meyer 的单例(如 this one)? 我知道 GOF 风格的单例(如 here )是可能的, 但我似乎无法让它与 Meyer 的单例一起工作: // ... public
Meyer 的单例类蓝图在头文件 temp.h 中声明。如果 temp.h 包含在两个单独的 .cpp 文件中,那么每个文件都有自己的蓝图,并且静态的东西对其他模块(即 *.o 或 *.cpp)不可见
到以下代码: class C { public: static C& Instance() { static C c; return c; }
假设我有一个类: class C{ int x_; int y_; public: C(int x, int y): x_(x), y_(y){} }; 然后我想从一个字符串中添加结构,它
我的代码: template class Singleton { public: static T& instance() { static T obj; re
我继承了一些在 g++ 9 和 10 下编译良好的代码,但是当打开优化时,两个编译器都会出现运行时错误(也就是说,编译 -O0 有效,但编译 -Og 会给出来自 MMU 的运行时错误.) 问题是在一个
我过来了this question最近,对 Instance() 函数的实现产生了疑问: class Configuration { public: static Configuration*
上周有人指出我有一段代码是这样的: #include namespace NSTest { class SingletonClass { public: static SingletonCl
我有以下实现基本 Meyers 单调的代码: #ifndef _cConfigFile_HH #define _cConfigFile_HH class cConfigFile { public:
Singleton(Meyers 的 Singleton)的以下使用惰性初始化的实现是否线程安全? static Singleton& instance() { static Singlet
我有一个在 Meyers 单例中运行的 boost 线程。它在我的程序期间愉快地运行。 当我的 Singleton 的析构函数被调用时(当程序加载出内存时)我设置了一个标志以便线程应该退出它的循环并触
Singleton(Meyers 的 Singleton)的以下使用惰性初始化的实现是否线程安全? static Singleton& instance() { static Singlet
我正在阅读 S. Meyers 的书“Effective C++。55 specific ways...”(第 3 版)。这本书中的某些内容,在规则 11 中,我不明白。所以,在下一个代码部分: Wi
我正在关注 Item6,它是 Scott Meyers 着的 Effective STL: 50 Specific Ways to Improve Your Use of the Standard T
我只是尝试使用 Scott Meyers 在“Effectice C++ in an Embedded Environment”中建议的 placement new 运算符。 DefaultM
我正在阅读 std::shared_ptr在Effective Modern C++14 Scott Meyers 的书。这是一段代码,作者说其中可能存在资源泄漏: int computePriori
Singleton(Meyers 的 Singleton)线程的以下使用延迟初始化的实现是否安全? static Singleton& instance() { static Singlet
所以我读了很多关于为什么这个实现不是线程安全的。但是我没有找到如何使其线程安全快速的答案?使其线程安全的变体是添加互斥体(或者在某些情况下,只需关键部分就足够了),但这会使该方法慢得多。那么是否有一种
我是一名优秀的程序员,十分优秀!