如何在UML类图中建模非成员聚合

时间:2019-02-12 18:16:45

标签: oop uml

在下面的UML图中,“帐户”具有订单的集合。根据大多数在线资源,这通常意味着Account类的实例与List相似。

但是实际上,对于具有持久性存储的现实世界Web应用程序来说,通常这不是帐户类的方式。它不会有订单列表作为实例。取而代之的是,其他一些控制器类将仅查询数据存储区,以查询属于某个帐户的所有订单。因此,在此类应用程序的UML类图中,这仍然是表示关系的正确方法吗?从数据库实体的角度看,基数以及聚合的概念看起来都是正确的。从阶级的角度来看,钻石是没有道理的。

还是应该显示一个具有getOrdersForAccount()方法的DataStore / DataManager并通过依赖关系(带箭头的虚线)将其连接到Account类和Orders类?

enter image description here

3 个答案:

答案 0 :(得分:3)

这取决于您要代表什么。

您已经拥有的类模型足以作为逻辑域模型,用于表达您域中实体之间的逻辑关系。这可能不是精确地在代码中实现软件的方式,但是它将指导您(和其他人)理解实体及其之间的关系,而不会陷入该实现细节中。在此级别上,您的图可能有一些设计选择(例如,强聚合可以说是一个设计选择,但可能不是,如枚举和键的使用那样),但实际上并没有太多的选择逻辑。如果有的话,您可以在此处放松一些设计选择并改善逻辑表达。

您可能还想提供一种表示方式,也是物理上实现OO代码的方式。这将是一个附加的类图,可以更精确地显示实现细节。在此图中,您将有更多的设计选择 -是否对订单使用集合(例如列表或其他集合类型类),数据访问方式是什么(适配器,管理器) ,ORM等)。在此级别上,您很可能会松散强聚合符号,因为在此级别上,我们正在谈论相互引用的类,而这些类最简单地使用基本关联来表示。您可能希望使用箭头和/或点符号来指示最终所有权和参考方向,以便更清楚地了解类之间的关系。

因此,我认为您的问题是关于模型,分析与设计中抽象水平的经典问题。感谢您提出要求!

答案 1 :(得分:1)

汇总仅表示:“如果删除帐户,则也需要删除订单”。

我也建议不要使用聚合(在大多数情况下),因为它只会给模型增加一点语义。在这种情况下,删除帐户后删除订单似乎很明显。在大多数情况下,聚合添加的唯一内容是(对于大多数钻石而言)对钻石的价值感到困惑或徒劳无功。

如果您有使用填充菱形的域,则应将其记录在建模规则中。使用共享聚合时,文档甚至是必需的,因为规范本身没有语义(请参见UML 2.5第110页的方框)。

答案 2 :(得分:1)

这取决于您对UML设计的理解程度。

如果目标是从UML生成代码,则可能需要添加您提到的类。 它看起来很像注册表模式: UML Diagram

  • 您可以添加抽象,以便更改DataManager的实现(如果您的DataManager是第三方,则只需从DataManagerImplementation调用API)即可。

  • 此后,根据实现的不同,一旦有了列表,如果需要保留它,则添加关联Account -> Order,如果可以将列表放在堆栈中,那么就很好了去。

C ++实例:

DataManagerImplementation *db = new DataManagerImplementation();
// Dependency injection
Account *acc = new Account(db);

然后进入“帐户”类别:

Account::Account(DataManager *db)
{
  // Fetch list at creation
  // Here 'orders' could be a member
  m_db = db;
  vector<Order*> *orders = m_db->GetOrders(this);
}

PS:我还建议在关联/聚合上放箭头(方向),否则它表示关联是双向的,因此帐户有一个指向订单列表的指针,每个订单也有一个指向订单的指针。帐户,我不确定是否需要。

要编辑PlantUML:http://www.plantuml.com/plantuml/png/SoWkIImgAStDuN99B4dqJSnBJ4yjyimjo4dDJSqhIIp9pCzJqDMjiLFmBqf9BK9ImuKk05Hcfw2afGHHYIbjfL2McboINsG3bj6oKz1oJoq1iuir79EJyqlpIZIve0m5a566IfYMEgJcfG0T2m00