管理类的聚合/合成成员之间的关系

时间:2009-05-31 16:50:02

标签: c++ relationship aggregation composition

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

在下面的C ++示例中:

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

    CDriver* m_pDriver;

    CEngine m_Engine;

    CDriverControls m_Controls;
};
在上面的例子中,汽车由发动机和一组驱动控制(通过组合)组成。汽车也必须有一个驱动程序(通过聚合)。

但这只能解释层次关系 - 司机属于汽车,发动机和控制装置也属于汽车。但是这些成员也彼此相关 - 驱动程序必须对控件执行操作,控件必须对引擎执行操作。这些关系也可以在多个方向上工作 - 引擎可以停止并导致控制器卡住,或者控件可能会疯狂旋转并伤害驱动程序?如果驾驶员不喜欢发动机的声音并离开汽车怎么办?这些关系如何运作?

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

三江源!

修改

正如回应所示,管理这种情况的一种方法是将汽车指向驾驶员,并给驾驶员一个指向汽车的指针等。这是有道理的,并解决了这个具体的例子。然而,在设计意义上,这增加了驾驶员的责任,其中该物体的任务是跟踪它属于哪辆车,但是这肯定是容器有责任跟踪哪些物体属于一起?同样,任务CCar管理这些关系将把CCar变成一个blob。是否有设计解决方案来处理这些关系?

5 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

问题应该是“我的申请是否需要这种关系?”例如,如果您正在为一辆简单的驾驶游戏驾驶汽车,您可能根本不需要担心天窗的电机。方向盘可能需要知道它连接到车轮,但不需要反向关系。

底线 - 在现实世界中,一切都是连通的,但在我们为解决特定问题而制造的那个世界的计算机模型中,它们并非如此。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

你可能想要汽车和司机之间的双向关联:

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

然后,驾驶员可以通过Car的公共界面访问Car的成员。

答案 4 :(得分: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可以使用很多控件的情况下,该类可以变得非常大,并且负责操作这些方向盘和手制动器对象。如果驾驶员进入与其他车辆没有相同控制的不同类型的汽车怎么办?现在驾驶员必须弄清楚如何使用它拥有的控制装置来操作车辆?额外的逻辑。额外的blob。

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

作为容器的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 );
}
相关问题