C++代码优化(四):通过分层来体现 “有一个“ 或 “用...来实现“
目录
1.引言
2.对象之间的关系
3.组合优于继承
4.示例
5.分层设计体现“用...来实现”
6.总结
1.引言
在C++代码优化中,通过分层(也称为模块化或模块化设计)来体现“有一个”或“用...来实现”的思想,可以使代码更加清晰、易于维护和扩展。分层设计将代码划分为不同的层次或模块,每个模块负责特定的功能,并通过接口与其他模块进行交互。
通过分层来体现 "有一个" 或 "用...来实现" 是一种合理的设计策略,用来表示类之间的关系和职责分离。这个方法通常用于避免过度使用继承,通过组合(Composition)来替代继承,实现更灵活的代码结构。
2.对象之间的关系
“有一个”(Has-a)关系表示一个类拥有另一个类作为其成员,而不是通过继承来共享行为。这样可以降低类之间的耦合度,减少代码复杂度,同时使代码更加灵活和易于维护。
“是一个”(is-a)关系通常用于描述面向对象编程中的继承关系。当一个类(子类或派生类)继承自另一个类(基类或父类)时,我们称子类“is-a”基类。这意味着子类不仅继承了基类的所有属性和方法(除非它们是私有的且未被重新实现),还可以添加自己的属性和方法或重写基类的方法以提供特定的实现。
面向对象编程中类与类之间的关系(一)-CSDN博客
面向对象编程中类与类之间的关系(二)-CSDN博客
3.组合优于继承
组合优于继承:什么情况下可以使用继承?-CSDN博客
4.示例
假设我们有一个 Engine
类代表引擎,Car
类代表汽车,Airplane
类代表飞机。Car
和 Airplane
都依赖于 Engine
的功能,但它们不应该继承 Engine
。我们可以通过组合来实现这种“有一个”关系。
#include <iostream>// 引擎类
class Engine {
public:void start() {std::cout << "Engine starts" << std::endl;}void stop() {std::cout << "Engine stops" << std::endl;}
};// 汽车类:用引擎来实现
class Car {
public:Car() : engine(new Engine()) {} // Car 拥有一个 Engine 对象~Car() { delete engine; }void drive() {engine->start();std::cout << "Car is driving" << std::endl;}void park() {std::cout << "Car is parked" << std::endl;engine->stop();}private:Engine* engine; // “有一个”关系
};// 飞机类:用引擎来实现
class Airplane {
public:Airplane() : engine(new Engine()) {} // Airplane 拥有一个 Engine 对象~Airplane() { delete engine; }void fly() {engine->start();std::cout << "Airplane is flying" << std::endl;}void land() {std::cout << "Airplane is landing" << std::endl;engine->stop();}private:Engine* engine; // “有一个”关系
};int main() {Car car;car.drive();car.park();Airplane airplane;airplane.fly();airplane.land();return 0;
}
5.分层设计体现“用...来实现”
分层设计通过组合对象实现代码功能,将复杂功能拆解成多个层次,每个类只负责一个独立的职责。比如在游戏开发中,一个 Character
类可以组合不同的 Weapon
或 Armor
,通过组合来动态决定某个角色的行为,而不是通过继承提供武器或护甲功能。
#include <iostream>// 武器基类
class Weapon {
public:virtual void use() = 0; // 纯虚函数,表示接口
};// 具体的武器
class Sword : public Weapon {
public:void use() override {std::cout << "Swinging a sword" << std::endl;}
};class Bow : public Weapon {
public:void use() override {std::cout << "Shooting an arrow" << std::endl;}
};// 角色类
class Character {
public:Character(Weapon* weapon) : weapon(weapon) {} // 角色“有一个”武器void attack() {weapon->use(); // 使用组合的武器实现攻击功能}private:Weapon* weapon; // “有一个”关系
};int main() {Sword sword;Bow bow;Character warrior(&sword); // 战士用剑攻击warrior.attack();Character archer(&bow); // 弓箭手用弓攻击archer.attack();return 0;
}
组合使得类可以更加灵活地组合功能。在上述例子中,Character
并不需要继承具体的武器类,而是通过组合 Weapon
接口,可以动态选择具体的武器类型。这样可以减少类的层次关系,使得代码更加模块化。
6.总结
优点
- 模块化:代码被划分为不同的模块,每个模块负责特定的功能。
- 可扩展性:如果需要更改用户输入方式或处理逻辑,只需替换相应的模块,而无需修改其他部分。
- 可维护性:代码结构清晰,易于理解和维护。
注意事项
- 内存管理:在示例中,我们手动管理内存(使用
new
和delete
)。在实际项目中,建议使用智能指针(如std::unique_ptr
或std::shared_ptr
)来自动管理内存。 - 依赖注入:可以使用依赖注入技术来进一步减少模块之间的耦合,提高代码的可测试性。
通过分层设计,我们可以更好地体现“有一个”或“用...来实现”的思想,使代码更加灵活和可维护。