面向对象:如何从多个实现中进行选择

MGA*_*MGA 7 c++ oop polymorphism casting

我是一个不错的程序程序员,但我是一个面向对象的新手(我是一个好老帕斯卡和C的工程师.)我觉得特别棘手的是选择其中一种方法来实现同样的目的.对于C++来说尤其如此,因为它的强大功能可以让你做任何你喜欢的事情,甚至可怕的事情(我想这里的权力/责任格言是合适的).

我认为这可能有助于我运行一个我正在与社区斗争的特定案例,以了解人们如何做出这些选择.我正在寻找的是与我的具体案例相关的建议,以及更一般的指针(没有双关语意).开始:

作为练习,我正在开发一个简单的模拟器,其中"几何表示"可以有两种类型:"圆"或"多边形".然后,模拟器的其他部分需要接受这些表示,并可能以不同方式处理它们.我已经提出了至少四种不同的方法来做到这一点.每个的优点/缺点/权衡取舍是什么?

答:功能重载

声明CirclePolygon作为不相关的类,然后重载需要几何表示的每个外部方法.

B:铸造

宣布一个enum GeometricRepresentationType {Circle, Polygon}.声明一个抽象GeometricRepresentation类和继承Circle,并Polygon从它.GeometricRepresentation有一个GetType()Circle和实现的虚方法Polygon.然后使用方法GetType()和switch语句将a GeometricRepresentation转换为适当的类型.

C:不确定合适的名字

声明枚举类型和抽象类,如B中所示.在这个类中,还创建函数Circle* ToCircle() {return NULL;}Polygon* ToPolygon() {return NULL;}.然后每个派生类重载相应的函数,返回this.这仅仅是动态铸造的重新发明吗?

D:一起束缚他们

将它们实现为具有枚举成员的单个类,该成员指示对象的类型.该类具有可以存储两种表示的成员.然后由外部方法决定不要调用愚蠢的函数(例如GetRadius()在多边形或GetOrder()圆上).

Dwa*_*ell 1

以下是我教给面向对象学生的一些设计规则(经验):

1)任何时候你想创建一个枚举来跟踪对象/类中的某些模式,你可以(可能更好)为每个枚举值创建一个派生类。

2)任何时候你编写一个关于对象(或其当前状态/模式/其他)的 if 语句,你都可以(可能更好)进行虚拟函数调用来执行一些(更抽象的)操作,其中原始的 then- 或else-sub-statement 是派生对象的虚函数的主体。

例如,不要这样做:

if (obj->type() == CIRCLE) {
    // do something circle-ish
    double circum = M_PI * 2 * obj->getRadius();
    cout << circum;
}
else if (obj->type() == POLY) {
    // do something polygon-ish
    double perim = 0;
    for (int i=0; i<obj->segments(); i++)
        perm += obj->getSegLength(i);
    cout << perim;
}
Run Code Online (Sandbox Code Playgroud)

做这个:

cout << obj->getPerimeter();

...

double Circle::getPerimeter() {
    return M_PI * 2 * obj->getRadius();
}

double Poly::getPerimeter() {
    double perim = 0;
    for (int i=0; i<segments(); i++)
        perm += getSegLength(i);
    return perim;
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,“更抽象”的概念是什么是非常明显的,周长。情况并非总是如此。有时它甚至连一个好名字都没有,这也是它很难“看见”的原因之一。但是,您可以将任何 if 语句转换为虚拟函数调用,其中“if”部分被函数的虚拟性替换。

就你的情况而言,我绝对同意 Avi 的答案,你需要一个基/接口类以及 Circle 和 Polygon 的派生子类。