是否使用 has-a(组合)或 is-a(继承)来建模汽车对象(及其部件,例如发动机)?

发布于 2024-08-14 21:47:12 字数 373 浏览 3 评论 0原文

我正在开发一个类库,其中将包含对象 Car。

困境是,汽车本身将是一个包含注册号和其他汽车一般信息等字段的类。

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

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

我该走哪条路?

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

谢谢

I am developing a class library which will include the object Car.

The dilemma is, Car itself will be a class with fields such as Registration Number, and other general information on the car.

But a car has an engine, chassis, etc. These objects need to be modelled too. Should they be classes embedded within Car? If not, what is the usage scenario of an embedded class?

I've learnt that composition is "part of", so you can model seperate classes and use the engine type, for example, at the field level of the car to achieve this. However, "aggregation", which is a "has a" relationship with the type being passed in the ctor, also applies (a car "has an" engine).

Which way do I go?

EDIT: I am currently on homework hence the lack of a reply from me. The class library is for a web app based around cars. I am a professional developer (I develop in .NET for a living but as a junior) so this is not a homework question.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

向日葵 2024-08-21 21:47:12

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

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

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

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

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

It really depends on your application.

For example, you could implement the wheels as separate classes, containing information about what tyre is on it, how worn it is, etc. but if your app doesn't even care about the wheels then the entire class is a waste of code.

I can see three use cases for composition:

  • The owning class has gotten overly complicated and should be broken down.
  • The owning class has multiple copies of a set of properties that could be mapped into a class. This allows you to bind all those properties together.
  • The contained object may need to be inspected or considered separately from the object that owns it (eg. you might want to move the Engine object to another car) or may be replaced as a single unit.

In summary: Use composition as a tool for encapsulating complexity or eliminating repetition. If it doesn't serve one of those purposes it probably isn't worth making a new class for.

单调的奢华 2024-08-21 21:47:12

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

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

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());
    }
}

A class should have as few responsibilities as possible and encapsulate and delegate other functionality to other classes. Lots of a small, simple classes that do one thing is a sign of a readable, stable codebase.

Yes, a car will "have" an engine, but I'd suggest using an interface for this and similar "has a" relationships. Again, depending on the professor, you might get bonus points for having a factory create different cars (appropriate, no?):

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());
    }
}
撩动你心 2024-08-21 21:47:12

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

“它们是否识别了引擎类”

“它是否具有像 Start( )”

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

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

Seeing as it is homework, and depending on the inclinations of your tutor/professor/teacher, you are probably better to go down the route of writing a separate classes for the engine, wheels and so on. Even though it may be completely over-engineered, and your application may not care about them, it is possible that your homework will be marked by standards such as:

"Did they identify an engine class"

"Does it have sensible methods like Start()"

"Mark them down for lumping everything in one big class that is actually simpler, because they clearly don't understand composition"

Or whatever, and not the kinds of standards that the more pragmatic people in this thread apply to their own designs.

别靠近我心 2024-08-21 21:47:12

仅将汽车模型分解为多个部分,这些部分将作为单独的实体暴露在汽车范围之外。另一种思考方式是,当你转动钥匙时,你真的了解你的车是如何启动的吗?对于典型的驾驶员而言,引擎盖下的所有东西都是一个大(且嘈杂)的黑匣子。汽车工程师了解车主需要维护的常见部件,并针对不同级别的用户交互进行了明确的设计,例如油尺或冷却液储液罐加注盖。

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

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

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

查看 FAA 使用的定义

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

飞机是指发动机驱动的飞机
比空气重的固定翼飞机,
在飞行中得到支持
空气对空气的动态反应
它的翅膀。

飞艇是指发动机驱动的
比空气轻的飞机
驾驶。

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

这是表格形式的前四个:

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

你明白了。

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

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

Only break down the model of the car into pieces that will be exposed as separate entities outside the scope of the car. Another way to think about it is do you really understand how your car gets started when you turn the key? As far as the typical driver is concerned, everything under the hood is one big (and noisy) black box. The auto-engineers know the common parts that need maintenance by the car owner and have explicitly designed them for a different level of user interaction, things like the oil dipstick or coolant reservoir refill cap.

Can you model each piece of the car? Sure. Is it helpful to model the individual spark plugs? Probably not.

Do you need cars with different attributes like color or size? Do you need cars with different capabilities like passenger or towing capacity? The one place that is different is if you need cars with different behaviors. This is where you really need to think about modeling a Driver object which has attributes, from simple ones like reaction-time to complex ones like aggressiveness.

Modeling vehicles as examples of object orientation or inheritance is problematic because the examples don't really explain the true distinctions between essential attributes that define a class. It's not new to StackOverflow but this question isn't a duplicate either, see this SO thread. I had this same discussion with a friend of mine and posted a log of it on my blog. Read up on the different aircraft types the FAA recognizes and how the regulations for each type are subdivided. There are lots of different types of aircraft, the biggest separation is between powered and unpowered.

Check out the definitions used by the FAA:

Aircraft means a device that is used
or intended to be used for flight in
the air.

Airplane means an engine-driven
fixed-wing aircraft heavier than air,
that is supported in flight by the
dynamic reaction of the air against
its wings.

Airship means an engine-driven
lighter-than-air aircraft that can be
steered.

There is also lighter-than-air and heavier-than-air. A hot-air balloon is unpowered and lighter-than-air. A blimp is powered and lighter-than-air. A glider is unpowered and heavier-than-air. A Boeing 757 is powered and heavier-than air but adds another category of 'fixed-wing' which is unlike a helicopter which is also powered and heavier-than-air but is 'rotary-wing'.

Here is the first four in the form of a table:

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

You get the picture.

You can't just say you'll model the engine separately from the car because a car without an engine might be a whole different animal. A car without an engine is nothing like a trailer, which also doesn't have an engine but never will either. In these cases neither 'is-a' nor 'has-a' fits in the concrete way we build objects. You don't declare a blimp as being a aircraft that 'is-a' lighter-than-air, so is a hot-air balloon. The fact that they are both lighter-than-air doesn't make them related in any way except the physics they exploit. The distinction is important because the rules and regulations that apply are different. From the other angle, we don't describe a blimp as a hot-air balloon that 'has-a' engine. The aircraft aren't physically related, the relationship is how they should be handled.

If you don't need to define your objects to that level of detail, you may not need to model them to that level of detail either.

柒夜笙歌凉 2024-08-21 21:47:12

汽车将是顶级层次结构对象。包括数字、ID 或描述等简单字段。
并且会有像Engine这样复杂的字段,它本身就是一个对象。

所以汽车看起来像:

class Car{
     String ID;
     Engine engine;
}

一个有关系。

Car will be an top hierarchy object. Including simple fields like Number, ID or description.
And will have complicated fields like Engine, which is an object by itself.

So the Car will look something like:

class Car{
     String ID;
     Engine engine;
}

That a has-a relation.

病毒体 2024-08-21 21:47:12

您可以根据一个标准来决定发动机、底盘等的类别
需要作为内部类(嵌入类)存在是
的实例
这些类可以在应用程序的其他地方使用。在这种情况下
决定很简单,就是让这些类单独存在
(不作为内部类)。

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

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

或者,可能不需要显式测试
中的方法
Car 中的引擎类和单元测试方法涵盖了引擎类代码
以及。然后它体现了Engine类与Car类的紧密集成
并且意味着它可以保留为内部类。

One criteria you can have to decide whether the classes for Engine, Chasis etc.
needs to be present as an inner class (embedded class) is whether instance of
these classes can be used elsewhere in your application. In such cases the
decision is simple and it is to make these classes exist separately
(not as inner classes).

Even if these classes are not used elsewhere in your application then other
criteria can be testability. With these classes embedded inside and with your
design is it possible to have unit tests that can appropriately test your
code providing a good coverage.

For example say, if you have made an instance variable which references an
Engine object and this variable is being initialized in the Constructor of Car.And
your Engine class has some methods which needs to be tested. Then how can
you add unit tests to check the code in Engine class ? Probably you would
have some methods in Car class which expose the behavior or Engine class allowing
you to write unit tests. Then the question is if there is a need to expose
the behavior of Engine class wouldn't it be better that the Engine class
stands on it own?

Alternatively there might not be a need to explicitly test the methods in
Engine class and unit testing the methods in Car covers the Engine class code
as well. Then it reflects tight integration of Engine class with the Car class
and would mean it can remain as an inner class.

云胡 2024-08-21 21:47:12

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

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

It depends on what it is you're trying to do. Trying to design a 'Car' class (or any other class for that matter) without an idea of the use cases is an exercise in futility.

You will design the classes and their relationships and interactions very differently depending on the use cases you're trying to enable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文