我正在开发一个包含Car对象的类库。
困境在于,汽车本身将是一个包含注册号等字段的类,以及有关汽车的其他一般信息。
但是汽车有发动机,底盘等。这些物体也需要建模。它们应该是嵌入汽车的课程吗?如果没有,嵌入式类的使用场景是什么?
我已经知道组合是“的一部分”,所以你可以模拟单独的类并使用引擎类型,例如,在汽车的现场级别实现这一点。然而,“聚合”,与ctor中传递的类型“有”关系,也适用(汽车“有”引擎)。
我该走哪条路?
编辑:我目前正在做作业因此缺乏回复。该类库适用于基于汽车的Web应用程序。我是一名专业开发人员(我以.NET开发为生,但作为一名大三学生)所以这不是一个功课问题。由于
答案 0 :(得分:4)
这实际上取决于你的申请。
例如,您可以将轮子作为单独的类来实现,包含有关轮胎在哪个轮胎上的信息,磨损程度等等。但是如果您的应用程序甚至不关心轮子那么整个课程都是浪费代码。
我可以看到三个组合用例:
总结:使用合成作为封装复杂性或消除重复的工具。如果它不能用于其中一个目的,那么可能不值得为它做一个新的课程。
答案 1 :(得分: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());
}
}
答案 2 :(得分:2)
看到它是家庭作业,并且根据您的导师/教授/老师的倾向,您可能最好沿着为引擎,车轮等编写单独的课程的路线。即使它可能完全过度设计,并且您的应用程序可能不关心它们,但您的作业可能会标记为以下标准:
“他们确定了引擎类”
“它是否有合理的方法,如Start()”
“将它们标记为将所有内容集中在一个实际上更简单的大类中,因为它们显然不理解组合”
或者其他什么,而不是这个线程中更务实的人适用于他们自己的设计的那种标准。
答案 3 :(得分:2)
仅将汽车的型号分解为将作为汽车范围之外的独立实体暴露的碎片。考虑它的另一种方法是,当你转动钥匙时,你真的了解你的汽车是如何开始的吗?就典型的驾驶员而言,引擎盖下的一切都是一个大而且嘈杂的黑匣子。汽车工程师知道汽车所有者需要维护的常见部件,并明确设计了不同级别的用户互动,例如油尺或冷却液储液器补充盖。
你能为汽车的每一块造型吗?当然。对各个火花塞进行建模是否有帮助?可能不是。
您是否需要具有不同属性(如颜色或尺寸)的汽车?您是否需要具有乘客或牵引能力等不同能力的汽车?一个不同的地方是你需要不同行为的汽车。这是你真正需要考虑对具有属性的Driver对象进行建模的地方,从简单的反应时间到复杂的反应时间。
将车辆建模为面向对象或继承的示例是有问题的,因为这些示例并未真正解释定义类的基本属性之间的真正区别。这对StackOverflow来说并不陌生,但这个问题也不重复,see this SO thread。我与我的一个朋友进行了同样的讨论并发布了log of it on my blog。阅读FAA认可的不同飞机类型以及每种类型的规定如何细分。有许多不同类型的飞机,最大的分离是动力和无动力之间。
查看definitions used by the FAA:
飞机表示使用的设备 或打算用于飞行 空气。
飞机表示由引擎驱动 固定翼飞机比空气重, 这是由飞行支持 空气的动态反应 它的翅膀。
飞艇意味着发动机驱动 比空气轻的飞机 转向。
还有比空气轻且比空气重的空气。热气球无动力且比空气轻。飞艇是动力的,比空气轻。滑翔机无动力且比空气重。波音757的动力比空气重,但增加了另一类“固定翼”,不像直升机,它也是动力的,比空气重,但是是“旋转翼”。
以下是表格中的前四个:
| Powered | Unpowered
---------------------------------------------------
Lighter-than-air | Blimp | Hot-air balloon
Heavier-than-air | 737 | Glider
你明白了。
你不能只说你将发动机与汽车分开建模,因为没有发动机的汽车可能是完全不同的动物。没有发动机的汽车就像拖车一样,也没有发动机,但也没有发动机。在这些情况下,'is-a'和'has-a'都不适合我们构建对象的具体方式。你没有宣称飞艇是一架“比空气更轻”的飞机,所以它是一个热气球。除了他们利用的物理学之外,它们都比空气更轻的事实并没有使它们以任何方式相关。区别很重要,因为适用的规则和规定是不同的。从另一个角度来看,我们并没有将飞艇描述为具有“发动机”的热气球。这架飞机没有物理关系,关系就是应该如何处理。
如果您不需要将对象定义到该详细程度,则可能不需要将它们建模到该详细程度。
答案 4 :(得分:0)
Car将成为顶级层次结构对象。包括数字,ID或描述等简单字段。 并且会有像Engine这样的复杂字段,它本身就是一个对象。
所以汽车看起来像是:
class Car{
String ID;
Engine engine;
}
这是一种关系。
答案 5 :(得分:0)
您可以决定引擎,Chasis等类的一个标准 需要作为内部类(嵌入类)存在是否是实例 这些类可以在您的应用程序的其他地方使用。在这种情况下 决定很简单,就是让这些课程分开存在 (不是内部类)。
即使这些类没有在你的应用程序的其他地方使用,那么其他的 标准可以是可测试性。将这些类嵌入内部并与您一起使用 设计是否可以进行单元测试,以便对您进行适当的测试 代码提供良好的覆盖范围。
例如,如果您创建了一个引用
的实例变量
引擎对象和此变量正在Car的构造函数中初始化
您的Engine类有一些需要测试的方法。那怎么可以
你添加单元测试来检查Engine类中的代码?可能你会
在Car类中有一些暴露行为或Engine类允许的方法
你要编写单元测试。那么问题是是否需要曝光
Engine类的行为不会比Engine类更好
它自己站着?
或者,可能不需要明确地测试方法中的方法
Car中引擎类和单元测试方法涵盖Engine类代码
同样。然后它反映了Engine类与Car类的紧密集成
并且意味着它可以保持为内在阶级。
答案 6 :(得分:0)
这取决于你想要做什么。试图在不知道用例的情况下设计一个“汽车”类(或任何其他类)是徒劳的。
您将根据您尝试启用的用例,以非常不同的方式设计类及其关系和交互。