UML之死

    《UML三大“硬伤”》这篇高展先生2002年发表在程序员杂志第5期的文章曾引起UML支持者、反对者、中立者之间的激烈辩论,这恰恰也是我旧事重提的原因。我现在和大家要讨论的是UML之死。

         是的,草木会败,人会苍老,太阳会燃尽……甚至是宇宙在若干亿年后也会消失不见,那么作为一门建模语言,UML也终究会死。

         据《论语  先进第十一》记载,孔子曾对子路说“未知生,焉知死?”,既然现在我们讨论UML之死,那么我们先从UML的出现说起。

         20世纪中期计算机技术快速推动着科技的发展,但随着计算机硬件性价比的逐步提高,所需的软件在成本、性能等方面很难满足要求。到了20世纪60年代末,落后的软件生产方式已经成为制约计算机发展的“瓶颈”,亦即出现了大家所熟知的“软件危机”。

为了解决“软件危机”引发的一系列问题,一些更好的软件生产方法和语言出现了,其中20世纪70年代出现的面向对象程序设计语言虽然开始并未引起多少人的重视,但最终对软件工程领域做的贡献大家有目共睹。20世纪80年代出现了一些面向对象的建模语言,经过十余年的知识沉淀,在BoochRumbaughjacobson三人的努力下于1996年发布了UMLUnified Modeling Language)这个一年后被OMG采纳为基于面向对象技术的标准建模语言。

UML的诞生我们可以看出,UML是在面向对象技术环境下生根发芽的。现在是2014年,UML已经足足发展了18年。如果把面向对象技术和UML比作人,那么OO早已是不惑之年,正奔走在通往知天命的路上;UML则在现代已是成年人,在孔子时代也马上弱冠了。现在UML具体是个什么样子呢?我想先从一个岗位来说——系统架构设计师。

最近十年“首席架构师”、“软件架构师”等一些舶来词越来越受大家的推崇,甚至比尔盖茨对自己最满意的称呼并非什么世界首富而是“首席软件架构师。就这样“系统架构设计师”自然而然地进入我国大门并被纳入国家水平资格认证体系中,成为高大上的象征。如果面试程序员应聘者的话问他职业规划的话,答案若非“称为架构师”大家会感到非常意外。作者也是随着大流在2011年也考了个“系统架构设计师”这个软件高级资格证书。

         那么我们不禁要问,系统架构设计师都做些什么?这个问题经常会成为论坛、群里面比较热的话题,大家的回答也往往很默契,那就是写写文档、画画图。

         好吧,据说架构师就是做这些工作,至少听说很多大型软件公司都有架构组专门来写文档、画图。写文档、画图的目的是什么呢?当然是描述系统的框架、网络架构、方案设计等这些内容,用一个比较专业的词语就是“系统建模”,而其中比较常用的工具就是UML。比如针对系统使用者或者其它角色和系统进行交互的行为我们可以用用例图结合说明来描述。建模主要是起到承上启下的作用,上接客户下接开发人员,让客户的需求能顺利体现在开发出来的产品上。听起来确实蛮不错的,起到桥梁的作用,可实际操作起来并非那么完美。试问,有多少客户懂得UML呢?甚至我要问,有多少开发人员懂得UML呢?好吧,怀疑产生了。

         确确实实,UML的普及存在很多问题。一来很多客户不懂UML但是又希望开发商能给出比较上档次的方案文档,另一方面开发人员难以忍受这些文档先行的事情发生,于是UML就这么被动地在夹缝里挣扎着。幸运的是UML并没有被折腾跨,而是一步步成长起来,IBM等那些软件巨头的开发体系就是佐证。所以UML现在不会死,刚成为成年人嘛,以后是青壮年时期。也就是说,UML在未来10-20年将大展身手,不怕你函数式编程的复苏,也不用担心革面向对象的命的技术出现。

         那么以后呢?面向对象会不会死?基于面向对象技术的UML会不会接着死?答案无疑是肯定的。文章开头我已经说过,任何事物都有其固有的生命周期,但面向对象现在很成熟,而人类在计算机软件发展方面很长时间没有颠覆式创新了。所以我们可以很乐观地估计,面向对象会继续为软件工程做着贡献,至少20年内面向对象不会死,那么UML也至少会存活20年之久。

         那么UML什么时候会真的死掉,这才是我们文章的议题?或许是面向对象技术死亡的那一刻起吧,谁知道呢?我只知道UML终究会死,到底何时死掉我一无所知。人向来对未知充满恐惧,而对UML的何时死亡我却充满兴趣。我所能想到的是,我孩子的孩子某天在我眼前空气中画了几个横竖线然后骄傲地告诉我:“爷爷、爷爷,我给您画出个好玩的游戏您快看看?”。

         作者:忆辛,20141127日写于羊城

 

<think> 我们正在讨论C++中的UML类图,特别是类图关系及其在C++中的实现。根据用户提供的引用,我们将详细解释UML类图中的几种关系,并给出C++代码示例。 UML类图关系主要包括:泛化(Generalization)、实现(Realization)、关联(Association)、聚合(Aggregation)、组合(Composition)和依赖(Dependency)。 1. **泛化(Generalization)**:表示继承关系,即子类继承父类。在C++中,使用类继承来实现。 ```mermaid classDiagram class Animal { +eat() } class Tiger { } Tiger --|> Animal ``` ```cpp // Animal.h class Animal { public: virtual void eat() { /* ... */ } }; // Tiger.h class Tiger : public Animal { // 可以重写eat方法,或者增加特有方法 }; ``` 2. **实现(Realization)**:表示类实现接口。在C++中,接口通常由纯虚函数构成的抽象类表示。 ```mermaid classDiagram class Flyable { <<interface>> +fly()* } class Bird { } Bird ..|> Flyable ``` ```cpp // Flyable.h class Flyable { public: virtual void fly() = 0; }; // Bird.h class Bird : public Flyable { public: void fly() override { /* 实现飞行 */ } }; ``` 3. **关联(Association)**:表示两个类之间有联系,可以是双向或单向的。关联关系可以有重复度(如1对多)。 ```mermaid classDiagram class Teacher { } class Student { } Teacher "1" --> "n" Student : 教授 ``` 在代码中,通常在一个类中包含另一个类的指针或引用。例如,一个老师有多个学生: ```cpp // Teacher.h class Student; // 前向声明 class Teacher { private: std::vector<Student*> students; // 1对多 public: void addStudent(Student* s) { students.push_back(s); } }; // Student.h class Teacher; class Student { private: Teacher* teacher; // 可选,如果双向关联 }; ``` 4. **聚合(Aggregation)**:表示整体与部分的关系,部分可以独立于整体存在。例如,学校由多个教师组成,但教师离开学校仍然存在。 ```mermaid classDiagram class School { } class Teacher { } School o-- Teacher : 拥有 ``` 在代码中,聚合通常表示为整体类中持有部分类的指针或引用,但整体不负责部分的生命周期。 ```cpp class Teacher; // 前向声明 class School { private: std::vector<Teacher*> teachers; // 聚合 public: void addTeacher(Teacher* t) { teachers.push_back(t); } // 注意:School不负责Teacher的销毁 }; ``` 5. **组合(Composition)**:表示更强的整体与部分关系,部分不能脱离整体存在。整体负责部分的生命周期。例如,鸟和翅膀的关系,鸟了,翅膀也不复存在。 ```mermaid classDiagram class Bird { } class Wing { } Bird *-- Wing : 由...组成 ``` 在代码中,组合通常表示为整体类中包含部分类的对象(或通过智能指针管理),并在整体销毁时部分也被销毁。 ```cpp class Wing { public: // ... }; class Bird { private: Wing leftWing; Wing rightWing; // 或者使用智能指针:std::unique_ptr<Wing> leftWing, rightWing; // 在Bird的构造函数中初始化它们,销毁时自动释放 }; ``` 6. **依赖(Dependency)**:表示一个类使用了另一个类,但关系较弱,通常是临时性的。例如,一个类的方法中使用了另一个类的对象作为参数。 ```mermaid classDiagram class Car { +repair(Engineer e) } class Engineer { } Car ..> Engineer : 依赖 ``` 代码中,在成员函数的参数或局部变量中使用: ```cpp class Engineer { /* ... */ }; class Car { public: void repair(Engineer& e) { // 依赖Engineer // 使用e进行修理 } }; ``` 重复度(Multiplicity)表示对象之间的数量关系: - 1:表示一个对象 - n:表示多个对象(用列表或集合存储) - 0..1:0个或1个 - *:0个或多个 例如,一个老师对应多个学生(1对多): ```cpp class Teacher { std::vector<Student*> students; // 重复度:1对多 }; ``` 总结: - 泛化:继承(`class Derived : public Base`) - 实现:实现接口(纯虚函数) - 关联:类之间的长期关系,通过指针或引用 - 聚合:部分可独立于整体(整体包含部分的指针,不负责生命周期) - 组合:部分与整体共存亡(整体直接包含部分对象或通过独占指针管理) - 依赖:短期使用关系(方法参数或局部变量) [^1]: [转载]UML类图关系全面剖析。这里再说一下重复度,其实看完了上面的描述之后,我们应该清楚了各个关系间的关系以及具体对应到代码是怎么样的,所谓的重复度,也只不过是上面的扩展,例如A和B有着“1对多”的重复度,那在A中就有一个列表,保存着B对象的N个引用,就是这样而已。 [^2]: UML类图关系模式及C++代码说明。在UML类图中的关系模式主要有以下几种: 泛化(Generalization),实现(Realization), 关联(Association), 聚合(Aggregation), 依赖(Dependency) 等.1. 泛化(Generalization)泛化关系: 是一种继承关系, 表示一般与特殊的关系, 它指定了子类如何特化父类的所有特征和行为. [^3]: C++ UML Tips。2)组合通常可以理解为“is a part of”。和聚合不同的是,如果类A组合类B,那么当A生命周期结束后,类B也随之结束,也就是说B不能脱离类A而存在。就如同鸟都有两只翅膀一样,当鸟消失了,翅膀也随之不存在了。 §§相关问题§§ 1. 在C++中如何正确实现聚合关系? 2. 组合关系与聚合关系在代码实现上有何具体区别? 3. 如何用C++代码表示一个类与多个类之间的多重关联? </think>### C++ 中 UML 类图关系详解 UML(统一建模语言)是描述软件系统结构的标准化方法,其中类图是核心建模工具。以下是 UML 类图关系及其在 C++ 中的实现详解: #### 一、六种核心关系类型 1. **泛化(Generalization)** - **描述**:继承关系(is-a 关系) - **UML 表示**:空心三角箭头(子类→父类) - **C++ 实现**:类继承 ```mermaid classDiagram class Animal class Tiger Tiger --|> Animal ``` ```cpp class Animal { public: virtual void eat() = 0; }; class Tiger : public Animal { // 泛化关系 public: void eat() override { /* 实现 */ } }; ``` 2. **实现(Realization)** - **描述**:类实现接口 - **UML 表示**:空心三角箭头+虚线(实现类→接口) - **C++ 实现**:纯虚函数 ```mermaid classDiagram class Flyable { <<interface>> +fly()* } class Bird Bird ..|> Flyable ``` ```cpp class Flyable { // 接口 public: virtual void fly() = 0; }; class Bird : public Flyable { // 实现关系 public: void fly() override { /* 飞行实现 */ } }; ``` 3. **关联(Association)** - **描述**:对象间长期持有的引用关系 - **UML 表示**:实线箭头(可双向) - **C++ 实现**:成员变量引用 ```mermaid classDiagram class Teacher class Student Teacher "1" --> "n" Student : 教导 ``` ```cpp class Student; // 前向声明 class Teacher { private: std::vector<Student*> students; // 1对多关联 public: void addStudent(Student* s) { students.push_back(s); } }; ``` 4. **聚合(Aggregation)** - **描述**:整体与部分可独立存在(has-a 关系) - **UML 表示**:空心菱形+实线(整体→部分) - **C++ 实现**:指针成员(不控制生命周期) ```mermaid classDiagram class School class Teacher School o-- Teacher : 雇佣 ``` ```cpp class Teacher; // 前向声明 class School { private: std::vector<Teacher*> teachers; // 聚合关系 public: void hireTeacher(Teacher* t) { teachers.push_back(t); } // 注意:不负责Teacher对象的销毁 }; ``` 5. **组合(Composition)** - **描述**:整体与部分共存亡(强 has-a 关系) - **UML 表示**:实心菱形+实线(整体→部分) - **C++ 实现**:对象成员或独占指针 ```mermaid classDiagram class Bird class Wing Bird *-- Wing : 拥有 ``` ```cpp class Wing { /* 翅膀实现 */ }; class Bird { private: Wing leftWing; // 组合关系:直接包含对象 Wing rightWing; public: Bird() : leftWing(), rightWing() {} // 生命周期绑定 }; ``` 6. **依赖(Dependency)** - **描述**:临时性使用关系 - **UML 表示**:虚线箭头(使用者→被依赖) - **C++ 实现**:参数传递或局部变量 ```mermaid classDiagram class Car class Mechanic Car ..> Mechanic : 维修 ``` ```cpp class Mechanic; // 前向声明 class Car { public: void repair(Mechanic& m) { // 依赖关系 m.fixEngine(*this); // 临时使用 } }; ``` #### 二、重复度(Multiplicity)表示法 表示对象间的数量关系: - `1`:一对一(默认) - `0..1`:零或一个 - `*`或`0..*`:零或多个 - `1..*`:一个或多个 - `n`:固定数量 **C++ 实现示例**: ```cpp class Department { private: std::vector<Employee*> employees; // 1对多:Department 1 → * Employee }; ``` #### 三、C++ 实现要点总结 | 关系类型 | 生命期控制 | 代码实现方式 | 示例场景 | |----------|------------|----------------------|-------------------| | 泛化 | 无 | 类继承 | 动物→老虎 | | 实现 | 无 | 纯虚函数 | 可飞行接口→鸟 | | 关联 | 弱 | 指针/引用成员 | 教师→学生 | | 聚合 | 无 | 外部管理指针 | 学校→教师 | | 组合 | 强 | 对象成员/unique_ptr | 鸟→翅膀 | | 依赖 | 无 | 参数/局部变量 | 汽车→修理工 | > **关键区别**:组合关系中,部分对象的生命周期由整体对象管理(整体销毁时部分必然销毁),而聚合关系中部分对象可独立存在[^3]。 #### 四、综合应用示例 ```mermaid classDiagram class University { -name: string +addDepartment(Department*) } class Department { -name: string +addCourse(Course*) } class Course { -code: string +assignProfessor(Professor*) } class Professor { -id: int +teach(Course&) } University "1" o-- "*" Department : 包含 Department "1" *-- "*" Course : 拥有 Professor "1" -- "*" Course : 教授 Course ..> Textbook : 使用 Professor --|> Person : 继承 ``` ```cpp // 组合关系:Department 拥有 Course 的生命周期 class Course { /*...*/ }; class Department { private: std::vector<std::unique_ptr<Course>> courses; // 组合 }; // 聚合关系:University 不控制 Department 生命周期 class Department; class University { private: std::vector<Department*> departments; // 聚合 }; // 依赖关系:Course 临时使用 Textbook class Textbook; class Course { public: void setTextbook(const Textbook& book) { /*...*/ } // 依赖 }; ``` [^1]: [转载]UML类图关系全面剖析。这里再说一下重复度,其实看完了上面的描述之后,我们应该清楚了各个关系间的关系以及具体对应到代码是怎么样的,所谓的重复度,也只不过是上面的扩展,例如A和B有着“1对多”的重复度,那在A中就有一个列表,保存着B对象的N个引用,就是这样而已。 [^2]: UML类图关系模式及C++代码说明。在UML类图中的关系模式主要有以下几种: 泛化(Generalization),实现(Realization), 关联(Association), 聚合(Aggregation), 依赖(Dependency) 等.1. 泛化(Generalization)泛化关系: 是一种继承关系, 表示一般与特殊的关系, 它指定了子类如何特化父类的所有特征和行为. [^3]: C++ UML Tips。2)组合通常可以理解为“is a part of”。和聚合不同的是,如果类A组合类B,那么当A生命周期结束后,类B也随之结束,也就是说B不能脱离类A而存在。就如同鸟都有两只翅膀一样,当鸟消失了,翅膀也随之不存在了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值