截至目前,我们已经探讨了三种对象间关系:组合(composition)、聚合(aggregation)和关联(association)。我们把最简单的一种留到最后——依赖(dependency)。
在日常语境中,我们用“依赖”一词表示某个对象为了完成特定任务而需要另一个对象。例如,如果你摔断了脚,你就依赖拐杖行走(但除此之外并不依赖)。花朵依赖蜜蜂授粉以结果或繁衍(但除此之外并不依赖)。
在软件中,依赖发生在一个对象调用另一个对象的功能以完成特定任务之时。这是一种比关联更弱的关系,但任何对被依赖对象的修改都可能破坏依赖方(调用方)的功能。依赖始终是单向关系。
一个你已多次见过的依赖示例是 std::ostream
。我们编写的类使用 std::ostream
仅用于向控制台输出信息,除此之外并无其他关系。
示例
#include <iostream>
class Point
{
private:
double m_x{};
double m_y{};
double m_z{};
public:
Point(double x = 0.0, double y = 0.0, double z = 0.0)
: m_x{x}, m_y{y}, m_z{z}
{
}
friend std::ostream& operator<<(std::ostream& out, const Point& point);
// Point 在此处依赖 std::ostream
};
std::ostream& operator<<(std::ostream& out, const Point& point)
{
// 由于 operator<< 是 Point 的友元,可直接访问其成员
out << "Point(" << point.m_x << ", " << point.m_y << ", " << point.m_z << ")";
return out;
}
int main()
{
Point point1{ 2.0, 3.0, 4.0 };
std::cout << point1; // 程序在此处依赖 std::cout
return 0;
}
在上例中,Point
与 std::ostream
并无直接关联,但因 operator<<
使用 std::ostream
打印 Point
,故 Point
对 std::ostream
存在依赖。
依赖与关联在 C++ 中的区别
依赖与关联常被混淆。在 C++ 中:
- 关联是一种关系,其中一个类以数据成员的形式保存对关联类的直接或间接“链接”。例如,
Doctor
类保存指向其Patient
的指针数组;你可以随时询问医生有哪些病人;Driver
类保存其拥有的Car
的 ID(整数成员),司机始终知道自己关联哪辆车。 - 依赖通常不作为成员存在。被依赖的对象往往是按需临时创建(如打开文件写入数据),或作为函数参数传入(如上述
operator<<
中的std::ostream
)。
幽默一刻
依赖(感谢 xkcd 的朋友):
当然,我们都知道这其实是一个自反关联!