【问题标题】:reducing duplicated methods?减少重复方法?
【发布时间】:2012-12-24 18:32:17
【问题描述】:

所以我正在开发一个 2D 空间模拟器,并且我有资源管理器“calc”来处理所有计算。比如来自calc.hpp

var calc::eccentricity (object A, object B);
var calc::distance     (object A, object B);
var calc::orbitV       (object A, object B);

等等。但是,我的程序结构方式是在我的 calc 课程中

private:
object *ship    //the currently controlled ship
object *targ    //target
object *ref     //reference (from which speeds, position, etc. are calculated)

为了使用第一个示例中给出的计算,我为每个计算函数编写了三个函数,如下所示:

var calc::ship_ecc      (object A){
    if(!ship)    //catches null pointers
        return NAN;
    return eccentricity(*ship, A);
}

var calc::ship_ref_ecc  (){
    if(!ref)    //catches null pointers
        return NAN;
    return ship_ecc(*ref);
}

var calc::ship_targ_ecc (){
    if(!targ)   //catches null pointers
        return NAN;
    return ship_ecc(*targ);
}

对于eccentricity,然后对于distanceorbitV 也是如此。所以我最终为每个计算提供了四个函数。正如您从calc.hpp 看到的那样,这会产生大量重复的代码。重复的代码是一件坏事。

我的问题是什么

有什么方法可以调用

calc.ship.targ.eccentricity();
calc.ship.ref.eccentricity(); //or variation thereof

calc.ship.targ(eccentricity);
calc.ship.ref(eccentricity);  //or variation thereof

而不是

calc.ship_targ_ecc();
calc.ship_ref_ecc();

?我想知道你是否可以做一些花哨的operator() 重载,或者传递一个函数,或者在calc 中创建一个friend 类。理想情况下,我应该只能访问行31 - 53,它们都是public

谢谢!

编辑:有一个 yall 的示例:https://ideone.com/jypJQS 这是它应该输出的内容以及它现在的工作方式

【问题讨论】:

  • 从设计的角度来看,您可能希望将所有计算封装到一个对象中。
  • 我已经让calc 成为我的计算资源经理,如果你是这个意思的话

标签: c++ oop class friend


【解决方案1】:

也许这改变了您当前的代码太多。但我认为 calc 中的函数应该是 object 的成员。所以你可以这样:

ship.eccentricity(target);

让我感到困惑(可能是这里最大的问题)是您似乎在 calc 对象(私有成员)中定义了一些硬关系。那些是为了什么?从代码中,我猜每个“船”都有一个 calc 对象。如果是,那么将代码添加到 object 而不是维护 object 和 calc 之间的 1-1 关系将是另一个原因。

【讨论】:

  • 实际上,在这个项目的first version 中我是这样做的,但我不喜欢它的耦合程度,所以我在最近对这个项目的重写中加入了它,给了我@987654322 @。另外,我设置它的方式是,calc 是一个单例,*ship 只是指向任何旧对象的指针,不一定是船。
【解决方案2】:

这可能需要一些重构,但我认为这是值得的。对于简单的游戏,您可以使用 OOP 和多态来解决问题。

首先,创建一个object 类。

 class Object {

 public:
    Object();
    ~Object();
 };

这个对象类将成为游戏中所有对象(船、角色等)的基础。然后,您将为您的 ship 创建一个子类。

 class Ship : public Object {


 };

这将允许对需要相同原理的未来对象进行轻松扩展。

在对象类中,您将拥有一些基本属性:

  • 物理(可选)
  • 尺寸
  • 速度(最后计算的速度)
  • 受控(bool - 当前控制船与否)

这将消除与calcship 类建立硬关系的需要。

接下来,您要将calc 类更改为通用类。您不想依赖单个船舶对象,这很麻烦。

选项 1

您可以为每个对象创建calc 类的实例。这个calc 实例可以访问objectship 类的现有属性。

选项 2

创建一个通用的calc 类,它需要您传递对船/对象实例的引用。 calc->eccentricity(&ship, target);

选项 3

在可能的manager 类或简单的“全局”变量中。您可以参考当前控制的船(如果您的系统是这样工作的,我不确定)。或者您可以存储船的索引,所有实例都保存在 vector<&Ship> 中。

在一个简单的游戏中,直接的 OOP 就足够了,但如果您想要更多的解耦,基于组件的游戏设计将是更好的选择(当然与 OOP 结合使用)。

【讨论】:

  • 因为我在我的 OP 中完全没有说明这一点,calc 是一个单身人士,我将任何旧的object 传递给它。如此有效的选项 2 就是我现在所拥有的。但是,请参阅我的回答,我将其更改为命名空间。另外,我已经有object 作为一个班级。而且我在对象类中没有像controlled 这样的变量,因为我知道如果calc.ship 指向某些东西,它就会受到控制。不是 OP 中最好的解释。
【解决方案3】:

所以我把它交给了/r/learnprogramming,我从 zzyzzyxx 那里得到了很好的答复(一如既往)。他的回答:

简单地使用需要两个或三个参数的函数有什么问题?他们不必在任何特殊的calc 类中。也许是 calc 命名空间。我不确定这对您的其余设计是否有意义,但是如果没有合理的默认值,将其设为成员函数以便任何东西都可以计算出它需要的目标和潜在的参考点怎么样?

所以基本上,不用担心所有这些calc.eccentricity(A, B)calc.ship_ecc(A)calc.ship_ref_ecc() 业务,直接说

calc.eccentricity(*calc.targ(), B)

另外,不要将 calc 设为单例,将其设为命名空间。
我现在就去做。

【讨论】:

    猜你喜欢
    • 2021-02-12
    • 2022-01-27
    • 1970-01-01
    • 2016-12-20
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    相关资源
    最近更新 更多