如何在 UML class 图中对非成员聚合建模
How to model a non member aggregate in UML class diagram
在下面的 UML 图中,Account 具有 Orders 的聚合。根据大多数在线资源,这通常意味着帐户 class 具有类似于列表的实例。
但实际上,对于具有持久存储的现实世界网络应用程序,帐户 Class 通常不是这样。它不会有订单列表作为实例。相反,一些其他控制器 class 将只查询一个数据存储,询问属于一个帐户的所有订单。那么在此类应用程序的 UML class 图中,这仍然是表示关系的正确方法吗?从数据库实体的角度来看,基数和聚合的概念看起来是正确的。只是从 Class 的角度来看钻石没有任何意义。
还是应该使用 getOrdersForAccount() 方法显示 DataStore/DataManager 并通过依赖关系(带箭头的虚线)将其连接到帐户 class 和订单 class?
聚合只是意味着:"if you delete the account you need to delete the orders as well"。
我还建议不要使用聚合(对于大多数情况),因为它只会为您的模型添加很少的额外语义。在这种情况下,删除帐户时删除订单似乎很明显。这里唯一添加的聚合是(在大多数情况下)关于该钻石的价值的一些混淆或一些徒劳的讨论。
如果您有一个使用实心菱形的域,则应将其记录在建模规则中。当使用共享聚合时,文档甚至是强制性的,因为规范中没有语义本身(参见 UML 2.5 第 110 页的框)。
这取决于你想表达什么。
您已有的 class 模型足以作为 逻辑域模型 ,表达您域中实体之间的逻辑关系。这可能不是您用代码精确实现软件的方式,但它将指导您(和其他人)理解实体及其关系,而不会陷入实现细节的泥潭。在这个级别,您的图表可能有一些设计选择(例如,强聚合可以说是一种设计选择,但它可能不是,就像使用枚举和键一样)但不会有那么多,也不会真正有损于底层逻辑。如果有的话,你可以在这里放松一些设计选择并改进逻辑表达。
您可能还需要提供 OO 代码如何物理实现的表示。这将是一个额外的 class 图表,可以更准确地显示实施细节。在此图中,您将有更多的设计选择——是否为订单使用集合(例如列表或其他集合类型class),您的数据是什么访问模式是(适配器、管理器、ORM 等)。在这个级别,您很可能会松开强聚合符号,因为在这个级别,我们正在讨论 classes 相互引用,这最简单地使用基本关联表示。您可能希望使用箭头 and/or 点符号来指示最终所有权和参考方向,以便更清楚 class 之间的关系。
因此,我认为您的问题是一个 classic 问题,涉及模型和分析与设计中的抽象级别。感谢提问!
这取决于您想要进行 UML 设计的深度。
如果您的目标是从 UML 生成代码,那么您可能需要添加您提到的 class。
它看起来很像注册表模式:
UML Diagram
您可以添加抽象,以便更改 DataManager 的实现(如果您的 DataManager 是第三方的,则只需从 DataManagerImplementation 调用 API)。
在那之后,根据你的实现,一旦你有了列表,如果你需要保留它然后添加关联 Account -> Order
,如果你可以接受堆栈上的列表那么你就可以开始了。
C++ 实例化示例:
DataManagerImplementation *db = new DataManagerImplementation();
// Dependency injection
Account *acc = new Account(db);
然后在 'Account' class:
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:我还建议把箭头(方向)放在association/aggregation上,否则这意味着关联是双向的,因此该帐户有一个指向订单列表的指针,并且每个订单也有一个指向帐户的指针,我不确定是否需要这个。
在下面的 UML 图中,Account 具有 Orders 的聚合。根据大多数在线资源,这通常意味着帐户 class 具有类似于列表的实例。
但实际上,对于具有持久存储的现实世界网络应用程序,帐户 Class 通常不是这样。它不会有订单列表作为实例。相反,一些其他控制器 class 将只查询一个数据存储,询问属于一个帐户的所有订单。那么在此类应用程序的 UML class 图中,这仍然是表示关系的正确方法吗?从数据库实体的角度来看,基数和聚合的概念看起来是正确的。只是从 Class 的角度来看钻石没有任何意义。
还是应该使用 getOrdersForAccount() 方法显示 DataStore/DataManager 并通过依赖关系(带箭头的虚线)将其连接到帐户 class 和订单 class?
聚合只是意味着:"if you delete the account you need to delete the orders as well"。
我还建议不要使用聚合(对于大多数情况),因为它只会为您的模型添加很少的额外语义。在这种情况下,删除帐户时删除订单似乎很明显。这里唯一添加的聚合是(在大多数情况下)关于该钻石的价值的一些混淆或一些徒劳的讨论。
如果您有一个使用实心菱形的域,则应将其记录在建模规则中。当使用共享聚合时,文档甚至是强制性的,因为规范中没有语义本身(参见 UML 2.5 第 110 页的框)。
这取决于你想表达什么。
您已有的 class 模型足以作为 逻辑域模型 ,表达您域中实体之间的逻辑关系。这可能不是您用代码精确实现软件的方式,但它将指导您(和其他人)理解实体及其关系,而不会陷入实现细节的泥潭。在这个级别,您的图表可能有一些设计选择(例如,强聚合可以说是一种设计选择,但它可能不是,就像使用枚举和键一样)但不会有那么多,也不会真正有损于底层逻辑。如果有的话,你可以在这里放松一些设计选择并改进逻辑表达。
您可能还需要提供 OO 代码如何物理实现的表示。这将是一个额外的 class 图表,可以更准确地显示实施细节。在此图中,您将有更多的设计选择——是否为订单使用集合(例如列表或其他集合类型class),您的数据是什么访问模式是(适配器、管理器、ORM 等)。在这个级别,您很可能会松开强聚合符号,因为在这个级别,我们正在讨论 classes 相互引用,这最简单地使用基本关联表示。您可能希望使用箭头 and/or 点符号来指示最终所有权和参考方向,以便更清楚 class 之间的关系。
因此,我认为您的问题是一个 classic 问题,涉及模型和分析与设计中的抽象级别。感谢提问!
这取决于您想要进行 UML 设计的深度。
如果您的目标是从 UML 生成代码,那么您可能需要添加您提到的 class。 它看起来很像注册表模式: UML Diagram
您可以添加抽象,以便更改 DataManager 的实现(如果您的 DataManager 是第三方的,则只需从 DataManagerImplementation 调用 API)。
在那之后,根据你的实现,一旦你有了列表,如果你需要保留它然后添加关联
Account -> Order
,如果你可以接受堆栈上的列表那么你就可以开始了。
C++ 实例化示例:
DataManagerImplementation *db = new DataManagerImplementation();
// Dependency injection
Account *acc = new Account(db);
然后在 'Account' class:
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:我还建议把箭头(方向)放在association/aggregation上,否则这意味着关联是双向的,因此该帐户有一个指向订单列表的指针,并且每个订单也有一个指向帐户的指针,我不确定是否需要这个。