【问题标题】:Question about design (inheritance, polymorphism)关于设计的问题(继承、多态)
【发布时间】:2010-04-09 20:55:04
【问题描述】:

我有一个关于我正在努力解决的问题的问题。希望你能忍受我。

假设我有一个 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 或类似的工具,但我想尽可能避免这种情况,因为我觉得可能有更好的方法来处理这个问题。

提前致谢!

【问题讨论】:

  • 干杯伙计们,非常感谢您的帮助。非常感谢,我在过去的几个小时里一直在重新思考这个问题。请在下面查看我的 cmets 每个答案。
  • 您可能想使用与“对象”不同的名称。

标签: design-patterns inheritance polymorphism


【解决方案1】:

处理这种耦合的一种方法是使用工厂。通用工厂创建对象和渲染器。 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

【讨论】:

    【解决方案2】:

    一种方法是允许对象通过返回适当类型的渲染器的 getRenderer() 方法创建自己的渲染器。这是工厂方法模式的一个示例。根据您的实现语言的特性,getRenderer 方法可能是您的父 Object 类中的一个抽象方法,它返回一个父 Renderer 类/接口的实例,具体的 Renderer 扩展/实现该实例。

    【讨论】:

      【解决方案3】:

      这可行吗?

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

      【讨论】:

        【解决方案4】:

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

        Dispatch(renderer)
        

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

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

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

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

        【讨论】:

        • 对,所以在这种情况下,每个渲染器都会有不同的功能。我不能使用通用基类,但似乎没有其他方法。
        【解决方案5】:

        这是看待这个问题的另一种方式。使渲染器成为对象的一部分。您可以为您创建的每个对象分配正确类型的渲染器,并且在每个对象上您将拥有一个

        Render(){
            myRenderer.Render(this)
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-03-09
          • 2011-01-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-14
          • 1970-01-01
          相关资源
          最近更新 更多