提问人:spaceKelan 提问时间:9/8/2023 最后编辑:spaceKelan 更新时间:9/12/2023 访问量:217
在类中定义结构的 UML 类图
UML Class Diagram with Struct Defined Inside Class
问:
对于包含仅在类生命周期内存在的结构的类的情况,UML 图会是什么样子?
免责声明:我看到有类似的问题,但我的不同之处在于,我使用的结构我在
类
中定义,如此处所述。我看到的关于如何在 UML 中使用结构的例子总是引用该类的特定结构。 请先看下面的 4 个问题。
示例代码
Parent.h
class Parent{
private:
uint8_t age;
struct{
uint16_t stepsADay;
uint8_t levelsADay;
}healthInfo;
public:
int setAge(uint8t_t a_age);
uint8_t getAge();
int setHealthInfo(uint16_t a_stepsADay,uint8_t a_levelsADay);
struct healthInfo getHealthInfo();
};
Parent.cpp
// omitting (de-)/constructor for readability
int Parent::setAge(uint8t_t a_age){
this->age = a_age;
return 0;
}
uint8_t Parent::getAge(){
return this->age;
}
int Parent::setHealthInfo(uint16_t a_stepsADay,uint8_t levelsADay){
this->healthInfo.stepsADay = a_stepsADay;
this->healthInfo.levelsADay= a_levelsADay;
return 0;
}
struct healthInfo Parent::getHealthInfo(){
return this->healthInfo;
}
main.cpp
#include "Parent.h"
uint32_t createMessage(Parent *thatParent){
healthInfo tmpHealthData=thatParent.getHealthInfo();
// create message to give to doctor
uint32_t messageToDoctor = (age <<24)
+ (tmpHealthData.stepsADay<<8)
+ (tmpHealthData.levelsADay);
return messageToDoctor;
}
int main() {
Parent papa = new Papa();
papa.setAge(54);
papa.setHealthInfo(1000,6);
// do other stuff ...
uint32_t message= createMessage(papa);
// send message ...
return 0;
}
UML
对我来说,结构在某种程度上类似于类似乎是合乎逻辑的,但由于我只将它与 w.r.t. 一起使用(当我不与父级交互时,我根本不需要该上下文)。从技术上讲,我在方法中短暂地调用该结构,但仅在那里。class
createMessage
我想将重要数据存储在一个有意义的事情中,直到我需要它来序列化这些信息以在其他地方使用它。
我有多个不同的结构类似于这个healthInfo
示例。
关注
当每个 1 个 UML 类时,我怀疑这是否实际上提高了整个 UML 图的整体可读性。但是,如果需要这样做,它会看起来像上面的那个吗?我不确定 Parent 中的 healthInfo 属性。我会说它是一种聚合,因为没有类就无法存在。
«struct»
struct
Parent
在类中定义 as 时使用 as 是错误的吗?
struct
return type
首先在类内创建是错误的吗?
structs
一旦我作为一个整体返回,我想在没有 getter 方法的情况下访问结构的属性。这很好还是我应该使用 getter 方法将它们设置为私有以使其“更干净”的编码?
struct
我认为有一些两极分化的意见,期待推理。
答:
在我看来,这似乎是合乎逻辑的,结构在某种程度上类似于一个类,当然它只是一个没有操作的类。
healhInfo
不能私密,你通过方法把它暴露在外面。getHealthInfo()
对于收容,应该是这样的:
请注意,应该写成 .建议类型以大写字母开头。healthInfo
HealthInfo
评论
- HealthInfo: HealthInfo
- healthInfo: HealthInfo
returntype
struct HealthInfo { uint16_t stepsADay; uint8_t levelsADay; } healthInfo;
HealthInfo
- «struct» 不是 UML 的构造型或关键字。你需要一个配置文件来定义这种刻板印象,实际上破坏了 UML 的语言不可知的方式。更好的可能是不要对它进行刻板印象并使用简单的类。任何编码人员都可以猜到这将像在 Cxx 语言中一样使用
struct
- 您可以从操作中返回任何类。
- 嵌套是 UML 中的一项基本内容,您可以以不同的方式展示它。使用嵌套连接器,或者通过放大外部类并将内部类呈现在边界内。
- 这是一个编码规则的问题,与UML设计不同。如果你有公共属性,你就不需要 getter/setter。在 SO 上有几个关于使用 getter/setter 的答案。
一般评论:UML 只有整数,没有您使用的特定整数。
评论
containment
aggregation
<<struct>>
总之
如果此设计可行,则需要在两个类之间定义两个不同的关系,并且:HealthInfo
Parent
第一个收容关系(圆圈加号),正如Jean-Baptise所解释的那样。这说明 UML 类的定义嵌套在 中。
HealthInfo
Parent
第二个复合聚合(黑菱形),它告诉父级有一个成员 healthInfo,并且该成员的生命周期由 Parent 管理(这是因为 C++ 使用值语义,除非您明确需要引用/指针)。
仅显示其中一种关系并不能正确捕获您的设计。
但是,外部泄漏的嵌套私有类型往往会导致隐藏的耦合。公共嵌套类型,甚至更好的非嵌套类型(在包含所有相关类的单独命名空间中)是更好的替代方法。
更多细节,包括设计问题
代码中的一些 C++ 问题
在 C++ 中,结构是一个类,唯一的区别是成员和基类默认是公共的。考虑到您已经向所有成员展示了公共访问权限,因此无需定义和使用构造型。«struct»
编辑:在 C++ 实现中,类和结构之间的区别仅在于成员和基类的可访问性。在 UML 中,您指定了公共成员,并且继承将始终是公共的(没有私有继承)。在这方面,类 X {public: .....
}; 和结构体 X {...};
将具有相同的语义和相同的模型。这就是为什么我说没有必要添加非标准的“结构”刻板印象。当然,如果您使用 C++ 配置文件并且 UML 构造型用于控制代码生成,则使用 «struct» 是有意义的。如果您想在设计和实现之间有一个清晰的映射,也是如此。
但是,结构的 C++ 和 C 用法之间的代码可能会混淆。下面指定一个匿名 (type) 并定义该类型的成员:struct
healthInfo
struct{
uint16_t stepsADay;
uint8_t levelsADay;
}healthInfo;
因此,不能返回任何类型,因为没有为该类型定义名称。编译器使用错误消息标记此问题。healthInfo
如果要定义私有类型并返回该类型的值,它应该如下所示,正如 Eljay 在评论中解释的那样:
struct HealthInfo {
uint16_t stepsADay;
uint8_t levelsADay;
}healthInfo;
返回类型将按如下方式指定:
HealthInfo Parent::getHealthInfo(){
return this->healthInfo;
}
为了避免类型和成员之间的这种混淆,建议的方法是在两个语句中定义类型和成员,即使它们位于同一类中。struct HealthInfo { ...};
HealthInfo healthInfo;
Parent
更严重的设计问题
用于返回的嵌套私有类型的问题在于,在类之外、其他类或独立函数中使用是具有挑战性的:
由于返回的类型在外部未知(private 是 private),因此其他类或非成员函数根本无法对此返回值执行太多操作。例如,它不能创建局部变量。幸运的是,现代 C++ 带来了 ,因此您可以编写:getHealthInfo()
Parent
Parent::HeathInfo x = ...
auto
auto x = papa.getHealthInfo();
cout << x.stepsADay;
但这非常烦人,因为 使你能够访问不应该在类外使用的内部结构。因此,这违背了私有嵌套类型的目的,并创建了隐藏的耦合。如果以后决定更改私有类型,则必须使用父类检查所有代码,以确定它们是否使用私有类型的内部结构,而不是将影响局限于类。auto
编辑:对于早于 C++11 的旧 C++ 标准,auto
关键字表示自动存储持续时间(例如函数的局部变量)而不是自动类型推导。在这种情况下,私有返回类型是完全无用的
这里是编译的更正代码
选择?
由于返回类型,如果要在外部使用信息,为什么要嵌套信息并将其设为私有?如果要在其他地方使用此类型,更好的方法是将嵌套类型设为公共类型,并将成员保持私有,如果应用上述建议,则很容易做到这一点。这样至少依赖关系是清晰干净的。
另一项改进是将成员函数设为 。createMessage()
Parent
评论
auto
struct Healthinfo{
Parent
HealtIinfo healthInfo
Parent
<<struct>>
uint8_t
Parent::Xxx
uint8_t
uint8_t
double
评论
struct
class
struct
class
struct
return type
stepsADay=100