
在图数据结构的应用中,我们常常需要为已有的顶点对象添加额外的属性,例如在位置列表中记录其位置索引。然而,实际开发中可能面临以下挑战:
针对这些约束,我们将探讨两种在不修改原始代码的前提下,实现O(1)属性访问的策略:组合(Composition)和继承(Inheritance)。
组合模式(Composition)是一种“has-a”关系,即一个类包含另一个类的实例作为其成员。通过这种方式,我们可以创建一个新的包装类,它持有原始顶点对象,并添加新的属性。
创建一个新的类MyVertex,该类内部包含一个GivenVertex类型的成员变量,以及我们需要添加的新属性(例如position)。所有对原始顶点属性的访问都将通过MyVertex中包含的GivenVertex实例进行。
以下C++代码展示了如何使用组合模式为GivenVertex添加一个position属性:
#include <iostream>
#include <cassert> // 用于断言测试
// 假设这是我们不能修改的原始顶点类
class GivenVertex {
private:
int color = 3; // 原始顶点的一个属性
// ... 其他原始属性和方法
public:
GivenVertex() {}
int getClr() {
return color;
}
// ... 其他原始公共方法
};
// 我们的新顶点类,使用组合模式
class MyVertex {
public:
int position; // 新增的属性
GivenVertex V; // 包含原始顶点对象
// 构造函数,接受原始顶点对象和新属性
MyVertex(GivenVertex originalVertex, int newPosition) {
this->V = originalVertex;
this->position = newPosition;
}
// 可以提供包装方法来访问原始顶点的属性,例如:
int getOriginalColor() {
return V.getClr();
}
};
int main() {
// 实例化一个原始顶点
GivenVertex gv = GivenVertex();
// 创建我们的新顶点,并为其赋予新属性
int pos = 7;
MyVertex mv = MyVertex(gv, pos);
// 验证新顶点是否正确包含了原始顶点属性和新属性
assert(mv.V.getClr() == 3); // 通过mv.V访问原始顶点属性
assert(pos == mv.position); // 直接访问新属性
std::cout << "Original Color: " << mv.V.getClr()
<< ", New Position: " << mv.position << std::endl; // 输出:Original Color: 3, New Position: 7
return 0;
}继承模式(Inheritance)是一种“is-a”关系,即一个类是另一个类的特殊类型。通过继承,子类可以扩展父类的功能,添加新的属性和方法。
创建一个新的类MyVertex,使其继承自GivenVertex。MyVertex将自动拥有GivenVertex的所有非私有成员,并可以在此基础上添加新的属性(例如position)。
以下C++代码展示了如何使用继承模式为GivenVertex添加一个position属性:
#include <iostream>
#include <cassert> // 用于断言测试
// 假设这是我们不能修改的原始顶点类
class GivenVertex {
private:
int color = 3; // 原始顶点的一个属性
public:
GivenVertex() {}
int getGivenClr() { // 注意:这里将getClr改名为getGivenClr以区分
return color;
}
// ... 其他原始公共方法
};
// 我们的新顶点类,使用继承模式
// 采用私有继承,表示MyVertex是基于GivenVertex实现的,但外部不应将其视为GivenVertex
class MyVertex : private GivenVertex {
public:
int position; // 新增的属性
// 构造函数,接受新属性
MyVertex(int newPosition) : GivenVertex() { // 调用基类构造函数
this->position = newPosition;
}
// 提供一个公共方法来访问基类的属性
int getMyClr() {
return getGivenClr(); // 直接访问基类的公共或保护方法
}
};
int main() {
// 创建我们的新顶点,并为其赋予新属性
int pos = 7;
MyVertex mv = MyVertex(pos);
// 验证新顶点是否正确包含了原始顶点属性和新属性
assert(mv.getMyClr() == 3); // 通过MyVertex的方法访问原始顶点属性
assert(pos == mv.position); // 直接访问新属性
std::cout << "Original Color: " << mv.getMyClr()
<< ", New Position: " << mv.position << std::endl; // 输出:Original Color: 3, New Position: 7
return 0;
}在实际应用中,选择组合还是继承取决于具体场景和面临的约束。
"私有嵌套类"的挑战: 这是最关键的限制。如果GivenVertex确实是一个私有嵌套类,这意味着:
在这种极端情况下,上述的组合和继承方案都无法直接应用,因为它们都假定我们能够获取到GivenVertex的定义或实例。如果无法获取GivenVertex的实例,那么唯一的选择可能就是回到使用外部映射(如HashMap或std::map),即使其最坏情况性能不满足O(1)的要求,也可能是唯一可行的方案。然而,如果原始图的实现提供了一个方法来获取GivenVertex的引用或指针(即使不能直接构造),那么组合模式仍有可能通过包装这些引用/指针来实现。
性能考量: 无论是组合还是继承,一旦对象被创建,对新增属性的访问都将是直接的成员访问,其时间复杂度为O(1),完全满足了性能要求。
设计原则:
在不修改原始代码的前提下为图顶点添加新属性,并在O(1)最坏时间复杂度内访问,组合模式和继承模式都是可行的解决方案。
然而,如果原始顶点类是一个私有嵌套类且无法在外部被实例化或继承,那么这两种直接扩展的方法将面临巨大挑战。在这种情况下,可能需要重新评估系统设计,或者在可接受的范围内考虑使用外部映射(如HashMap),并接受其在特定场景下的性能折衷。在大多数情况下,如果能够访问原始顶点的实例或其公共接口,组合模式通常是更稳健且推荐的选择。
以上就是在不修改原始代码的情况下为图顶点添加新属性的策略的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号