关于设计的问题(继承,多态)

时间:2010-04-09 20:55:05

标签: design-patterns inheritance polymorphism

我对我正在努力解决的问题有疑问。希望你能忍受我。

想象一下,我有一个Object类,表示物理对象层次结构的基类。后来我继承它来创建一个Object1D,Object2D和Object3D类。这些派生类中的每一个都将具有一些特定的方法和属性。例如,3d对象可能具有下载渲染器要使用的3d模型的功能。

所以我有这样的事情:

class Object {};
class Object1D : public Object { Point mPos; };
class Object2D : public Object { ... };
class Object3D : public Object { Model mModel; };

现在我有一个名为Renderer的独立类,它只需要一个Object作为参数,然后渲染它:-) 以类似的方式,我想支持不同类型的渲染器。例如,我可以拥有每个对象可以依赖的默认值,然后为某种对象提供其他特定的渲染器:

class Renderer {};  // Default one
class Renderer3D : public Renderer {};

这就是我的问题。渲染器类需要将Object作为参数,例如在构造函数中,以便检索渲染对象所需的任何数据。

到目前为止一切顺利。但Renderer3D需要获取一个Object3D参数,以便不仅获得基本属性,还获得3d对象的特定属性。

构造函数看起来像这样:

CRenderer(Object& object);
CRenderer3D(Object3D& object);

现在我如何以通用方式指定它?或者更好的是,有没有更好的方法来设计它?

我知道我可以依赖RTTI或者类似的但我想尽可能避免这种情况,因为我觉得可能有更好的方法来解决这个问题。

提前致谢!

5 个答案:

答案 0 :(得分:4)

处理这种耦合的一种方法是使用工厂。通用工厂创建对象和渲染器。 2D工厂创建2D对象和兼容的2D渲染器,3D工厂创建3D对象和兼容的3D渲染器。

abstract class Factory {
  abstract Object createObject();
  abstract Renderer createRenderer();
}

class 2DFactory {
  Object createObject() { return new 2DObject(); }
  Renderer createRenderer() { return new 2DRenderer(); }
}

// similarly for 3D

class Client {
  Client(Factory factory) { ... }
  void render() {
    factory.createRenderer().render(factory.createObject());
  }
}

因此,如果您不混淆不同工厂的产品,您可以保持客户端代码清洁。如果客户端代码只处理一个对象系列和渲染器一次,将它传递给合适的工厂是微不足道的,然后让它在不知道具体类型的情况下使用对象和渲染器。对此的一种变体是让对象通过工厂方法创建兼容的渲染器,如suggested by Jason

另一种可能性是使用模板/泛型,但这是特定于语言的。您的实现语言看起来像C ++,所以我冒险朝这个方向努力。您可以使用模板专业化:

template<class T> class Renderer {
  void render(T object) { ... }
};

template<> class Renderer<Object3D> {
  void render(Object3D object) {
    // render the 3D way
  }
};

// similarly for 2D

答案 1 :(得分:3)

一种方法是允许Objects通过getRenderer()方法创建自己的渲染器,该方法返回相应类型的渲染器。这是Factory Method模式的一个示例。根据实现语言的功能,getRenderer方法可以是父Object类中的抽象方法,返回父Renderer类/接口的实例,特定呈现器扩展/实现。

答案 2 :(得分:1)

这可行吗?

template<typename T> class Renderer {};
class Renderer3D : public Renderer<Object3D> {};

答案 3 :(得分:1)

听起来你正在寻找双重调度模式。要使用它,可以向基类添加一个抽象方法,如下所示:

Dispatch(renderer)

Object的每个子类然后重写Dispatch并在提供的渲染器上为其类型调用适当的方法:

Object2D.Dispatch(renderer)
{
   renderer.Render2D(self)
}

您还可以使用接口使其更通用。创建一个用于呈现每种类型对象的接口,并让您的调度方法检查是否支持正确的接口:

Object2D.Dispatch(renderer)
{
    render2d = render as IRender2D
    if render2d found
        render2d.Render(self)
}

答案 4 :(得分:0)

这是另一种看待这个的方法。使渲染器成为对象的一部分。您可以为您创建的每个对象以及您将拥有的每个对象

分配正确类型的渲染器
Render(){
    myRenderer.Render(this)
}