4

我正在开发一个包含对象 Car 的类库。

困境是,汽车本身将是一个具有诸如注册号等字段的类,以及汽车的其他一般信息。

但是汽车有引擎、底盘等。这些对象也需要建模。它们应该是嵌入在 Car 中的类吗?如果不是,嵌入式类的使用场景是什么?

我了解到组合是“一部分”,因此您可以对单独的类进行建模并使用引擎类型,例如,在汽车的字段级别来实现这一点。但是,“聚合”是与在 ctor 中传递的类型“有”的关系,也适用(汽车“有”引擎)。

我该走哪条路?

编辑:我目前正在做作业,因此我没有回复。类库用于基于汽车的 Web 应用程序。我是一名专业开发人员(我以 .NET 为生,但作为一名初级开发人员),所以这不是一个家庭作业问题。

谢谢

4

7 回答 7

4

这实际上取决于您的应用程序。

例如,您可以将轮子实现为单独的类,包含有关轮胎上的轮胎、磨损程度等信息,但如果您的应用程序甚至不关心轮子,那么整个类就是浪费代码。

我可以看到三个组合用例:

  • 拥有类变得过于复杂,应该分解。
  • 所属类具有一组属性的多个副本,这些属性可以映射到一个类中。这允许您将所有这些属性绑定在一起。
  • 包含的对象可能需要与拥有它的对象分开检查或考虑(例如,您可能希望将 Engine 对象移动到另一辆车),或者可能作为一个单元被替换。

总结:使用组合作为封装复杂性或消除重复的工具。如果它不能满足其中一个目的,则可能不值得为此创建一个新课程。

于 2009-12-16T07:54:57.827 回答
4

一个类应该具有尽可能少的职责,并封装其他功能并将其委托给其他类。许多做一件事的小而简单的类是可读、稳定的代码库的标志。

是的,汽车将“拥有”引擎,但我建议为此使用界面以及类似的“拥有”关系。同样,根据教授的不同,您可能会因让工厂制造不同的汽车而获得加分(合适,不是吗?):

public class Car
{
    private Engine engine;
    public Car(Engine engine)
    {
        this.engine = engine;
    }

    public void accelerate()
    {
        this.engine.goFaster();
    }

    public void decelerate()
    {
        this.engine.goSlower();
    }

}

public interface Engine
{
    public void goFaster();
    public void goSlower();
}


public class ReallyFastEngine implements Engine
{
    public void goFaster()
    {
    // some code that goes really fast
    }
    public void goSlower()
    {
    // some code that goes slower
    }    
}

public class NotAsFastEngine implements Engine
{
    public void goFaster()
    {
    // some code that goes not as fast
    }
    public void goSlower()
    {
    // some code that goes slower
    }    
}

public class CarFactory()
{
    public static Car createFastCar()
    {
         return new Car(new ReallyFastEngine());
    }

    public static Car createNotAsFastCar()
    {
         return new Car(new NotAsFastEngine());
    }
}
于 2009-12-16T15:47:32.193 回答
2

仅将汽车模型分解为将作为汽车范围之外的单独实体公开的部分。另一种思考方式是,您真的了解转动钥匙时汽车是如何启动的吗?就典型的驱动程序而言,引擎盖下的一切都是一个大(且嘈杂)的黑匣子。汽车工程师知道需要车主维护的常见部件,并明确设计它们以适应不同级别的用户交互,例如油尺或冷却液储液罐加注盖。

你能对汽车的每一部分进行建模吗?当然。对单个火花塞进行建模是否有帮助?可能不是。

您是否需要具有不同属性(如颜色或尺寸)的汽车?您是否需要具有不同功能的汽车,例如载客或牵引能力?一个不同的地方是您是否需要具有不同行为的汽车。这是您真正需要考虑对具有属性的 Driver 对象进行建模的地方,从简单的属性(如反应时间)到复杂的属性(如攻击性)。

将车辆建模为面向对象或继承的示例是有问题的,因为这些示例并没有真正解释定义类的基本属性之间的真正区别。这对 StackOverflow 来说并不新鲜,但这个问题也不是重复的, 请参阅这个 SO 线程。我和我的一个朋友进行了同样的讨论,并在我的博客上发布了一个日志。阅读 FAA 认可的不同飞机类型以及如何细分每种类型的规定。有很多不同类型的飞机,最大的区别是有动力和无动力的。

查看FAA 使用的定义

飞机是指用于或打算用于空中飞行的设备。

飞机是指由发动机驱动的比空气重的固定翼飞机,在飞行中由空气对其机翼的动态反应支撑。

飞艇是指由发动机驱动的可操纵的轻于空气的飞机。

还有比空气轻和比空气重的。热气球是无动力的,比空气轻。飞艇是有动力的,比空气轻。滑翔机是无动力的,比空气重。波音 757 有动力且比空气重,但增加了另一类“固定翼”,这与直升机不同,后者也有动力且重于空气,但属于“旋转翼”。

这是表格形式的前四个:

                 |  Powered   |    Unpowered
---------------------------------------------------
Lighter-than-air |  Blimp     |    Hot-air balloon 
Heavier-than-air |  737       |    Glider

你得到图片。

您不能只说将发动机与汽车分开建模,因为没有发动机的汽车可能是完全不同的动物。没有引擎的汽车与拖车完全不同,拖车也没有引擎,但也永远不会。在这些情况下,“is-a”和“has-a”都不适合我们构建对象的具体方式。您不会将飞艇宣布为“比空气轻”的飞机,热气球也是如此。除了它们所利用的物理学之外,它们都比空气轻这一事实并没有使它们以任何方式相关。区别很重要,因为适用的规则和法规不同。从另一个角度来看,我们不会将飞艇描述为“有”引擎的热气球。飞机没有物理关系,

如果您不需要将对象定义到该详细级别,则可能也不需要将它们建模到该详细级别。

于 2009-12-16T21:57:51.003 回答
2

鉴于这是家庭作业,并且根据您的导师/教授/老师的倾向,您最好沿着为引擎、车轮等编写单独的课程的路线走下去。即使它可能完全过度设计,并且您的应用程序可能不关心它们,您的作业也可能会被以下标准标记:

“他们是否确定了引擎类别”

“它是否有像 Start() 这样的合理方法”

“将他们标记为一个实际上更简单的大类中的所有内容,因为他们显然不理解作文”

或者其他什么,而不是这个线程中更务实的人应用于他们自己的设计的那种标准。

于 2009-12-16T12:50:59.570 回答
0

Car 将是一个顶层层级对象。包括简单的字段,如编号、ID 或描述。并且会有像Engine这样的复杂字段,它本身就是一个对象。

所以汽车看起来像:

class Car{
     String ID;
     Engine engine;
}

那是一种有关系。

于 2009-12-16T08:03:53.027 回答
0

这取决于你想要做什么。尝试在不了解用例的情况下设计“汽车”类(或任何其他类)是徒劳的。

根据您尝试启用的用例,您将非常不同地设计类及其关系和交互。

于 2009-12-17T06:16:53.563 回答
0

您必须决定引擎、底盘等的类是否
需要作为内部类(嵌入式类)存在的一个标准是
这些类的实例是否可以在应用程序的其他地方使用。在这种情况下,
决定很简单,就是让这些类单独存在
(而不是作为内部类)。

即使这些类没有在您的应用程序的其他地方使用,其他
标准也可以是可测试性。将这些类嵌入到您的
设计中,就可以进行单元测试,以适当地测试您的
代码,从而提供良好的覆盖率。

例如,如果您创建了一个引用
Engine 对象的实例变量,并且该变量正在 Car 的构造函数中初始化。并且
您的 Engine 类有一些需要测试的方法。那么如何
添加单元测试来检查 Engine 类中的代码呢?可能您
在 Car 类中有一些方法可以公开行为或 Engine 类允许
您编写单元测试。那么问题是如果需要暴露
Engine 类的行为,Engine 类独立存在不是更好
吗?

或者,可能不需要显式测试
Engine 类中的方法,并且对 Car 中的方法进行单元测试也涵盖了 Engine 类代码
。然后它反映了 Engine 类与 Car 类的紧密集成,
这意味着它可以保留为内部类。

于 2009-12-16T08:26:10.510 回答