在统一建模语言(UML)中,依赖关系是一种重要的模型元素,用来表示一个事物(比如类、组件或包)依赖于另一个事物的情况。依赖关系通常表示一个事物的定义或实现部分地或完全依赖于另一个事物。
UML 依赖关系可以细分为以下几种类型:
一个类(客户端)在其方法中使用另一个类(供应商)的实例。例如:
Car 类使用 Engine 类来提供动力。- #include
-
- class Engine {
- public:
- void start() {
- std::cout << "Engine started" << std::endl;
- }
-
- void stop() {
- std::cout << "Engine stopped" << std::endl;
- }
- };
-
- class Car {
- public:
- Car() {
- engine = new Engine();
- }
-
- void start() {
- engine->start();
- }
-
- void stop() {
- engine->stop();
- }
-
- private:
- Engine* engine;
- };
-
- int main() {
- Car car;
- car.start();
- car.stop();
-
- return 0;
- }
ReportGenerator 类使用 DataSource 类来获取数据。- #include
- #include
-
- class DataSource {
- public:
- virtual ~DataSource() {}
- virtual std::vector<int> getData() = 0;
- };
-
- class JdbcDataSource : public DataSource {
- public:
- std::vector<int> getData() override {
- std::cout << "Getting data from JDBC data source" << std::endl;
- return {1, 2, 3};
- }
- };
-
- class CsvDataSource : public DataSource {
- public:
- std::vector<int> getData() override {
- std::cout << "Getting data from CSV data source" << std::endl;
- return {4, 5, 6};
- }
- };
-
-
- class ReportGenerator {
- public:
- ReportGenerator(DataSource* dataSource) {
- this->dataSource = dataSource;
- }
-
- void generateReport() {
- std::vector<int> data = dataSource->getData();
- // ... 生成报表 ...
- }
-
- private:
- DataSource* dataSource;
- };
-
- int main() {
- // 使用 JDBC 数据源
- JdbcDataSource* jdbcDataSource = new JdbcDataSource();
- ReportGenerator reportGenerator1(jdbcDataSource);
- reportGenerator1.generateReport();
-
- // 使用 CSV 数据源
- CsvDataSource* csvDataSource = new CsvDataSource();
- ReportGenerator reportGenerator2(csvDataSource);
- reportGenerator2.generateReport();
-
- return 0;
- }
一个类负责创建另一个类的实例。例如:
Factory 类负责创建 Product 类的实例。- #include
-
- class Product {
- public:
- virtual ~Product() {}
- virtual void doSomething() = 0;
- };
-
- class ConcreteProductA : public Product {
- public:
- void doSomething() override {
- std::cout << "ConcreteProductA do something" << std::endl;
- }
- };
-
- class ConcreteProductB : public Product {
- public:
- void doSomething() override {
- std::cout << "ConcreteProductB do something" << std::endl;
- }
- };
-
- class Factory {
- public:
- virtual ~Factory() {}
- virtual Product* createProduct() = 0;
- };
-
- class ConcreteFactoryA : public Factory {
- public:
- Product* createProduct() override {
- return new ConcreteProductA();
- }
- };
-
- class ConcreteFactoryB : public Factory {
- public:
- Product* createProduct() override {
- return new ConcreteProductB();
- }
- };
-
- int main() {
- Factory* factory = new ConcreteFactoryA();
- Product* productA = factory->createProduct();
- productA->doSomething();
-
- factory = new ConcreteFactoryB();
- Product* productB = factory->createProduct();
- productB->doSomething();
-
- return 0;
- }
Document 类负责创建 Paragraph 类的实例。- #include
- #include
-
- class Section {
- public:
- Section(const std::string& text) {
- this->text = text;
- }
-
- void print() {
- std::cout << text << std::endl;
- }
-
- private:
- std::string text;
- };
-
- class Document {
- public:
- void addSection(const std::string& text) {
- sections.push_back(new Section(text));
- }
-
- void print() {
- for (Section* section : sections) {
- section->print();
- }
- }
-
- private:
- std::vector
sections; - };
-
- int main() {
- Document document;
- document.addSection("This is the first section.");
- document.addSection("This is the second section.");
- document.print();
-
- return 0;
- }
一个类的方法接受另一个类的实例作为参数。例如:
FileReader 类的方法接受一个 File 类的实例作为参数。- #include
- #include
-
- class File {
- public:
- File(const std::string& path) {
- this->path = path;
- }
-
- const std::string& getPath() const {
- return path;
- }
-
- private:
- std::string path;
- };
-
- class FileReader {
- public:
- void readFile(const File& file) {
- std::ifstream ifs(file.getPath());
- if (ifs.is_open()) {
- std::string line;
- while (getline(ifs, line)) {
- std::cout << line << std::endl;
- }
- ifs.close();
- } else {
- std::cout << "Error opening file" << std::endl;
- }
- }
- };
-
- int main() {
- File file("C:/test.txt");
- FileReader fileReader;
- fileReader.readFile(file);
-
- return 0;
- }
List 类的 Add 方法接受一个要添加的元素作为参数。- #include
- #include
-
- template <typename T>
- class List {
- public:
- void add(const T& element) {
- elements.push_back(element);
- }
-
- void print() {
- for (const T& element : elements) {
- std::cout << element << " ";
- }
- std::cout << std::endl;
- }
-
- private:
- std::vector
elements; - };
-
- int main() {
- List<int> list;
- list.add(1);
- list.add(2);
- list.add(3);
- list.print();
-
- return 0;
- }
一个类的方法返回另一个类的实例。例如:
Database 类的方法返回一个 Connection 类的实例。- #include
-
- class Connection {
- public:
- Connection() {
- std::cout << "Creating connection" << std::endl;
- }
-
- ~Connection() {
- std::cout << "Closing connection" << std::endl;
- }
- };
-
- class Database {
- public:
- Connection* getConnection() {
- return new Connection();
- }
- };
-
- int main() {
- Database database;
- Connection* connection = database.getConnection();
-
- // 使用连接...
-
- delete connection;
-
- return 0;
- }
Parser 类的方法返回一个 Document 类的实例。- #include
- #include
-
- class Document {
- public:
- Document(const std::string& text) {
- this->text = text;
- }
-
- void print() {
- std::cout << text << std::endl;
- }
-
- private:
- std::string text;
- };
-
- class Parser {
- public:
- Document* parse(const std::string& filePath) {
- std::ifstream ifs(filePath);
- if (ifs.is_open()) {
- std::string text;
- while (getline(ifs, text)) {
- // ... 解析文本 ...
- }
- ifs.close();
- return new Document(text);
- } else {
- std::cout << "Error opening file" << std::endl;
- return nullptr;
- }
- }
- };
-
- int main() {
- Parser parser;
- Document* document = parser.parse("C:/test.txt");
-
- if (document != nullptr) {
- document->print();
- delete document;
- }
-
- return 0;
- }
指模板实例化时,将模板类绑定到具体的参数上。
类模板是指可以生成不同类型对象的类。类模板的实例化需要指定具体的类型参数。如果一个类的模板实例化依赖于另一个类,那么就表示该类模板依赖于另一个类。例如:
List 类模板可以生成不同类型元素的列表。- #include
- #include
-
- template <typename T>
- class List {
- public:
- void add(const T& element) {
- elements.push_back(element);
- }
-
- void print() {
- for (const T& element : elements) {
- std::cout << element << " ";
- }
- std::cout << std::endl;
- }
-
- private:
- std::vector
elements; - };
-
- int main() {
- // 生成 int 型元素的列表
- List<int> list1;
- list1.add(1);
- list1.add(2);
- list1.add(3);
- list1.print();
-
- // 生成 string 型元素的列表
- List
list2; - list2.add("Hello");
- list2.add("World");
- list2.add("!");
- list2.print();
-
- return 0;
- }
Map 类模板可以生成不同类型键值对的映射。- #include
- #include
-
- template <typename K, typename V>
- class Map {
- public:
- void add(const K& key, const V& value) {
- elements[key] = value;
- }
-
- void print() {
- for (const auto& pair : elements) {
- std::cout << pair.first << " -> " << pair.second << std::endl;
- }
- }
-
- private:
- std::map
elements; - };
-
- int main() {
- // 生成 int 型键值对的映射
- Map<int, int> map1;
- map1.add(1, 10);
- map1.add(2, 20);
- map1.add(3, 30);
- map1.print();
-
- // 生成 string 型键值对的映射
- Map
map2; - map2.add("Hello", "World");
- map2.add("Goodbye", "Cruel World");
- map2.print();
-
- return 0;
- }
实现关系是指一个类(实现类)承诺实现另一个类(接口)定义的契约。接口定义了一组方法和属性,但并不提供具体的实现,而是描述了一种行为规范。实现类则提供了这些方法和属性的具体实现。例如:
Animal 类定义一个 Speak 接口。Dog 类实现 Animal 接口,并提供具体的 Speak 方法实现。- #include
-
- class Animal {
- public:
- virtual void speak() = 0; // 纯虚函数,没有具体实现
- };
-
-
- class Dog : public Animal {
- public:
- void speak() override {
- std::cout << "Woof!" << std::endl;
- }
- };
-
- int main() {
- Dog dog;
- dog.speak();
-
- return 0;
- }
实现关系的特点:
扩展关系是一种 UML 关系类型,表示一个用例(扩展用例)在某些条件下扩展另一个用例(基本用例)的功能。扩展关系通常用于表示可选的、非必须的功能。
扩展关系的关键点:
扩展关系的应用场景:
扩展关系的优点
扩展关系与其他关系的比较:
扩展关系示例:
- #include
-
- class IControl {
- public:
- virtual void Click() = 0;
-
- protected:
- virtual void DoClick() = 0;
- };
-
- class Button : public IControl {
- public:
- void Click() {
- std::cout << "按钮被点击了!" << std::endl;
- DoClick();
- }
-
- protected:
- void DoClick() override {
- std::cout << "按钮执行点击操作!" << std::endl;
- }
- };
-
- class Security {
- public:
- virtual bool VerifyUser() = 0;
-
- protected:
- virtual void DoVerifyUser() = 0;
- };
-
- class LoginUseCase {
- public:
- void Execute() {
- std::cout << "登录用例正在执行..." << std::endl;
- // ...
-
- // 检查是否需要安全检查。
- if (isSecurityCheckNeeded) {
- Security security;
- if (!security.VerifyUser()) {
- std::cout << "登录失败:身份验证失败!" << std::endl;
- return;
- }
- }
-
- // ...
- }
-
- private:
- bool isSecurityCheckNeeded = true;
- };
-
- int main() {
- LoginUseCase loginUseCase;
- loginUseCase.Execute();
-
- return 0;
- }
Control 类
Button 类
Security 类
LoginUseCase 类
- #include
-
- class Order {
- public:
- virtual double calculatePrice() = 0; // 纯虚函数,没有具体实现
-
- protected:
- double originalPrice;
-
- public:
- Order(double originalPrice) {
- this->originalPrice = originalPrice;
- }
- };
-
- class DiscountCalculator {
- public:
- virtual bool isEligibleForDiscount(const Order& order) = 0; // 纯虚函数,没有具体实现
-
- virtual double calculateDiscount(const Order& order) = 0; // 纯虚函数,没有具体实现
- };
-
- class OrderWithDiscount : public Order {
- public:
- OrderWithDiscount(double originalPrice) : Order(originalPrice) {}
-
- double calculatePrice() override {
- DiscountCalculator calculator;
- if (calculator.isEligibleForDiscount(*this)) {
- return originalPrice - calculator.calculateDiscount(*this);
- } else {
- return originalPrice;
- }
- }
- };
-
- class SimpleDiscountCalculator : public DiscountCalculator {
- public:
- bool isEligibleForDiscount(const Order& order) override {
- return order.originalPrice >= 100;
- }
-
- double calculateDiscount(const Order& order) override {
- return order.originalPrice * 0.1;
- }
- };
-
- int main() {
- Order* order = new OrderWithDiscount(120);
- std::cout << "原价:" << order->originalPrice << std::endl;
- std::cout << "优惠价:" << order->calculatePrice() << std::endl;
-
- return 0;
- }
在这个例子中,OrderWithDiscount 类扩展了 Order 类,并使用了 DiscountCalculator 类来计算优惠价格。
- #include
- #include
-
- class File {
- public:
- virtual bool isInfected() = 0; // 纯虚函数,没有具体实现
-
- protected:
- std::string path;
-
- public:
- File(const std::string& path) {
- this->path = path;
- }
- };
-
- class VirusScanner {
- public:
- virtual bool scan(const File& file) = 0; // 纯虚函数,没有具体实现
- };
-
- class FileUpload {
- public:
- virtual void upload(const File& file) = 0; // 纯虚函数,没有具体实现
- };
-
- class FileUploadWithVirusScan : public FileUpload {
- public:
- FileUploadWithVirusScan() {}
-
- void upload(const File& file) override {
- VirusScanner scanner;
- if (!scanner.scan(file)) {
- std::cout << "文件 " << file.path << " 含有病毒,无法上传" << std::endl;
- return;
- }
-
- // 上传文件...
-
- std::cout << "文件 " << file.path << " 上传成功" << std::endl;
- }
- };
-
- class SimpleVirusScanner : public VirusScanner {
- public:
- bool scan(const File& file) override {
- std::ifstream ifs(file.path);
- if (ifs.is_open()) {
- // 扫描文件内容...
-
- return true;
- } else {
- return false;
- }
- }
- };
-
- int main() {
- File* file = new File("C:/test.txt");
- FileUploadWithVirusScan uploader;
- uploader.upload(*file);
-
- return 0;
- }
在这个例子中,FileUploadWithVirusScan 类扩展了 FileUpload 类,并使用了 VirusScanner 类来扫描文件是否含有病毒。
假设有一个ReportGenerator类,它负责生成报告,并使用DataSource类来获取所需的数据。在这种情况下,ReportGenerator依赖于DataSource,因为它需要DataSource提供的数据来完成其功能。在UML图中,这种依赖关系会用一条从ReportGenerator指向DataSource的带有开放箭头的虚线来表示。