
在软件开发中,我们经常会遇到需要为现有对象添加额外属性或行为的场景,但又受到多种限制。例如,当我们面对一个图的顶点接口实现时,可能需要为每个顶点存储一个额外的属性(如其在位置列表中的索引),同时必须满足以下严格条件:
传统的解决方案,如使用 HashMap(在C++中通常是 std::unordered_map),虽然平均时间复杂度为O(1),但其最差情况时间复杂度为O(n),因此不符合严格的O(1)最差情况要求。直接尝试通过继承来扩展顶点类,又会受限于私有嵌套类的访问权限。
面对这些挑战,我们需要一种既能规避原始代码修改,又能满足性能和访问限制的策略。
组合模式是一种强大的设计模式,它允许我们将一个类的实例作为另一个类的成员。通过这种方式,我们可以创建一个新的“包装”类,它内部包含原始对象,并在此基础上添加新的属性。这种方法完美地解决了不允许修改原始代码和私有嵌套类的限制。
核心思想: 创建一个新的类 MyVertex,它将包含一个 GivenVertex 类型的成员变量,以及我们想要添加的新属性(例如 position)。
优点:
示例代码:
#include <iostream> // 替换 <bits/stdc++.h> 以提高可读性
#include <cassert> // 用于断言
// 假设这是我们不能修改的原始顶点类
class GivenVertex {
private:
int color = 3; // 原始属性
// ... 可能还有其他私有成员
public:
GivenVertex() {}
int getClr() {
return color;
}
// ... 可能还有其他公共方法
};
// 我们的新类,使用组合模式来扩展功能
class MyVertex {
public:
int position; // 新添加的属性
GivenVertex V; // 包含原始GivenVertex的实例
// 构造函数,接收一个GivenVertex实例和新属性的值
MyVertex(GivenVertex originalVertex, int newPosition) {
this->V = originalVertex;
this->position = newPosition;
}
// 可以添加其他方法来封装对V的操作,例如:
int getOriginalColor() {
return V.getClr();
}
};
int main() {
// 创建一个原始的GivenVertex实例
GivenVertex originalGV = GivenVertex();
// 使用组合模式创建我们的MyVertex
int pos = 7;
MyVertex myExtendedVertex = MyVertex(originalGV, pos);
// 验证新属性和原始属性是否正确
assert(myExtendedVertex.V.getClr() == 3); // 访问原始属性
assert(pos == myExtendedVertex.position); // 访问新属性
std::cout << "Original Color: " << myExtendedVertex.V.getClr()
<< ", New Position: " << myExtendedVertex.position << std::endl;
return 0;
}在上述代码中,MyVertex 通过持有 GivenVertex 的一个实例 V,成功地将 GivenVertex 的功能和我们需要的 position 属性结合起来。当我们创建一个 MyVertex 对象时,它会包含一个 GivenVertex 对象,并且我们可以通过 myExtendedVertex.V 访问 GivenVertex 的原始功能,通过 myExtendedVertex.position 访问新添加的属性。
继承是面向对象编程中扩展功能的一种常见方式。如果原始类不是私有嵌套类,并且允许被继承,那么创建一个子类并在其中添加新属性也是一个可行的方案。
核心思想: 创建一个新类 MyVertex,它继承自 GivenVertex,并在 MyVertex 中添加新的属性 position。
局限性:
示例代码(假设 GivenVertex 可被继承):
#include <iostream>
#include <cassert>
// 假设这是可被继承的原始顶点类
class GivenVertex {
private:
int color = 3;
public:
GivenVertex() {}
int getGivenClr() { // 更改方法名以避免与MyVertex中的getClr混淆
return color;
}
};
// 使用继承模式创建我们的MyVertex
class MyVertex : private GivenVertex { // 这里使用私有继承
public:
int position;
MyVertex(int newPosition) {
this->position = newPosition;
}
// 提供一个公共方法来访问父类的功能
int getMyClr() {
return getGivenClr(); // 通过父类方法访问原始属性
}
};
int main() {
int pos = 7;
MyVertex myExtendedVertex = MyVertex(pos);
// 验证新属性和原始属性
assert(myExtendedVertex.getMyClr() == 3); // 访问原始属性
assert(pos == myExtendedVertex.position); // 访问新属性
std::cout << "Original Color (via MyVertex): " << myExtendedVertex.getMyClr()
<< ", New Position: " << myExtendedVertex.position << std::endl;
return 0;
}在这个继承示例中,MyVertex 私有继承自 GivenVertex。私有继承意味着 GivenVertex 的公共和保护成员在 MyVertex 中变为私有。因此,为了从外部访问 GivenVertex 的功能(如 getGivenClr()),MyVertex 必须提供一个公共的“转发”方法(如 getMyClr())。
重要提示: 考虑到原始问题中“私有嵌套类”的限制,继承方案在大多数情况下是不可行的。组合模式是更通用且更符合原始约束的解决方案。
在选择扩展现有对象的方式时,请考虑以下因素:
原始类的可访问性和可修改性:
性能要求(O(1) 最差情况):
关系建模:“is-a” vs. “has-a”:
代码复杂性与维护:
当需要在不修改原始代码、满足O(1)最差情况检索,且原始对象为私有嵌套类等严格限制下为对象添加新属性时,组合模式(通过创建新类来包装原始对象并添加新属性)是最推荐且最稳健的解决方案。它能够有效规避私有嵌套类的限制,并保证属性检索的性能。
尽管继承模式在面向对象编程中是扩展功能的基础,但其适用性受到原始类可访问性和可继承性的严格限制。在面临不可修改或私有嵌套类时,应优先考虑组合模式,以实现灵活、高效且符合约束的扩展。
以上就是在不修改原始代码的情况下为现有对象添加新属性的策略的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号