2

我正在使用聚合和组合为模拟创建实体。

在以下 C++ 示例中:

class CCar
{
    CCar( CDriver* pDriver )
    { m_pDriver = pDriver; }

    CDriver* m_pDriver;

    CEngine m_Engine;

    CDriverControls m_Controls;
};

在上面的例子中,一辆汽车由一个发动机和一组驾驶控制(按组合)组成。一辆车还必须有一个司机(通过聚合)。

但这只是解释了层次关系——驾驶员属于汽车,引擎和控件也属于汽车。但是这些成员也都相互关联——驾驶员必须对控件执行操作,控件必须对引擎执行操作。这些关系也可以在多个方向上发挥作用——发动机可能会熄火并导致控制装置失灵,或者控制装置可能会疯狂旋转并伤害驾驶员?如果驾驶员不喜欢发动机的声音并离开汽车怎么办?这些关系如何运作?

我正在从经常与其他对象交互的许多不同对象中合成许多不同的实体,并且对如何以设计的方式管理这些关系感兴趣。

谢谢你!

编辑:

正如回复所暗示的,管理此问题的一种方法是将汽车指向驾驶员,并为驾驶员提供指向汽车的指针等。这很有意义并解决了这个具体的例子。然而,在设计意义上,这增加了驾驶员的责任,这个对象的任务是跟踪它属于哪辆车,但这肯定是容器的责任来跟踪哪些对象属于一起?同样,让 CCar 负责管理这些关系会将 CCar 变成一个 blob。是否有处理这些关系的设计解决方案?

4

5 回答 5

1

您将它们构建到每个类的方法中。您所描述的是每个班级的行为。您的要求表明关系也是双向的。您的 Controls 类将具有采用 Engine 参数并调用其方法的方法。发动机将对其 RPM、HP、扭矩等进行限制,由控制器控制,这些限制将内置于其中(例如,“如果您的 RPM 降得太低,则熄火”)。

它不仅仅是作曲。您将行为和规则构建到方法中。这些方法可能采用表达您需要的参数。

于 2009-05-31T16:55:02.310 回答
1

问题应该是“我的应用程序需要这种关系吗?” 例如,如果您正在为一个简单的驾驶游戏模拟驾驶汽车,您可能根本不需要担心天窗的电机。方向盘可能需要知道它与车轮相连,但不需要反向关系。

底线 - 在现实世界中,一切都是相互联系的,但在我们为解决特定问题而建立的那个世界的计算机模型中,它们不是。

于 2009-05-31T17:02:27.933 回答
1

强调接口而不是组合、聚合或继承可能很有用。例如,可以编写您的驱动程序类,使其可以使用“方向盘”接口。自然,您的方向盘实现提供了“方向盘”接口的实现。同样,汽车提供了一个“汽车接口”,可以编写方向盘实现以利用该接口。

您的实现可能使用组合、聚合和继承。但在这种方法中,真正驱动设计的是接口。无论您在给定实例中使用组合、聚合还是继承,都只是实现细节。

于 2009-06-01T02:56:02.213 回答
0

您可能需要汽车和驾驶员之间的双向关联:

CCar( CDriver* pDriver ) :
     m_pDriver(pDriver)
{
    m_pDriver->SetCar(this);
}

然后驱动程序可以通过 Car 的公共接口访问 Car 的成员。

于 2009-05-31T16:56:04.710 回答
0

要解决这个问题,首先要确定每个组件的作用。

CCar - 一个容纳组件和聚合体的容器。

CDriver - 表示驱动程序的对象

CEngine - 表示引擎的对象

等等

对于一个小而简单的程序,应该使用一个简化的设计,给司机一个指向汽车的指针

CCar( CDriver* pDriver )
{
m_pDriver = pDriver;
m_pDriver->SetCar(this);
}

对于更大的应用程序,如果 CCar 可能需要添加新组件等,这是不可接受的,并且让驾驶员可以访问整个 CCar 将是糟糕的设计实践——在这里,驾驶员不仅可以更换方向盘,还可以更换汽车颜色等,这显然不是本意。

让驱动程序访问它需要的位怎么样?

m_pDriver->SetSteeringWheel( m_SteeringWheel );
m_pDriver->SetHandBrake( m_HandBrake );

这解决了这个问题,现在驾驶员无法访问汽车的其他属性(例如颜色)。但是,它赋予 CDriver 类更多的职责。CDriver 可以使用很多控件,类可以变得非常大,并负责操作这些方向盘和手刹对象。如果驾驶员乘坐的车辆类型与其他车辆不同,该怎么办?现在驾驶员必须弄清楚如何使用其拥有的控件来操作车辆?额外的逻辑。额外的斑点。

所有这一切的解决方案是使用中介类(或变体)来控制驾驶员与车辆的交互方式。这可以通过以下两种方式之一来完成,驾驶员可以拥有汽车的中介,它控制驾驶员与汽车的交互方式。或者,驾驶员可以为它必须处理的汽车的每个组件或集合设置一个调解器。这可能是一个更好的解决方案,因为调解器可以重复用于不同类型的汽车。中介必须能够处理组件之间的双向关系。

作为容器的 CCar 负责维护中介,从而维护其组件之间的关系。就是它应该的样子。

中介者负责处理组件之间的这种关系。

class CMediatorDriverToSteeringWheel
{
CMediatorDriverToSteeringWheel( CDriver* pDriver, CSteeringWheel* pSteeringWheel )
{
m_pDriver = pDriver;
m_pSteeringWheel = pSteeringWheel;
m_pDriver->AddMediator(this);
m_pSteeringWheel->AddMediator(this);
}
};

... 

CCar::CCar( CDriver* pDriver )
{
m_pDriver = pDriver;
new CMediatorDriverToSteeringWheel( m_pDriver, &m_SteeringWheel );
new CMediatorDriverToHandbrake( m_pDriver, &m_HandBrake );
}
于 2009-06-02T13:40:13.207 回答