我读过的大多数关于面向对象编程的书都使用了Shape带有Shape.draw()成员函数的Dog类或带有成员函数的类Dog.talk()或类似的东西来演示多态的概念.现在,这对我来说是一个混乱的根源,这与多态性无关.
class Dog : public Animal
{
public:
...
virtual void talk() { cout << "bark! bark!" << endl; }
...
};
Run Code Online (Sandbox Code Playgroud)
虽然这可能只是一个简单的例子,但我无法想象一个好的方法可以让它在一个更复杂的应用程序中运行,其中Dog.talk()可能需要访问另一个类的声音子程序,例如玩bark.mp3而不是使用cout输出.比方说我有:
class Audio
{
public:
...
void playMP3(const string& filename)
...
};
Run Code Online (Sandbox Code Playgroud)
什么是Audio.playMP3()在设计时从Dog.talk()内部访问的好方法?做Audio.playMP3()静电?传递函数指针?已经Dog.talk()返回它想打,让程序处理它的另一部分文件名?
Gre*_*ill 10
一种方法可能是让Dog构造函数引用Audio类的实例,因为狗(通常)会产生噪音:
class Dog: public Animal {
public:
Dog(Audio &a): audio(a) {}
virtual void talk() { audio.playMP3("bark.mp3"); }
private:
Audio &audio;
};
Run Code Online (Sandbox Code Playgroud)
您可以像这样使用它:
Audio audioDriver;
Dog fido(audioDriver);
fido.talk();
Run Code Online (Sandbox Code Playgroud)
我的解决方案是让Dog类在bark函数中传递音频设备.
狗应该不是一个指针存储到音频设备的时候,这不是它的职责之一.如果你走这条路,你最终得到的构造函数占用了二十几个对象,基本上指向了应用程序的所有其余部分(它也需要一个指向渲染器的指针,所以可以绘制它.它需要一个指向地面的指针,并告诉输入经理告诉它去哪里,...........疯狂就是这样.
这些都不属于狗.如果需要与另一个对象通信,请将该对象传递给需要它的特定方法.
狗的责任是吠叫.树皮发出声音.因此bark方法需要一种生成声音的方法:必须传递对音频对象的引用.整个狗不应该关心或知道这一点.
class Dog: public Animal {
public:
virtual void talk(Audio& a);
};
Run Code Online (Sandbox Code Playgroud)
按照同样的逻辑,形状不应该自己绘制.渲染器绘制对象,这就是它的用途.矩形对象的责任只是矩形.这个职责的一部分是能够在绘制矩形时将必要的绘图数据传递给渲染器,但绘制本身不是它的一部分.