设计模式概述以及原则)
什么是设计模式设计模式是软件开发中针对常见问题的可复用解决方案共 23 种分为三类创建型6 种关注对象的创建方式如单例、工厂结构型7 种关注类与对象的组合如适配器、装饰器行为型10 种关注对象间的职责分配与通信如策略、观察者学习设计模式的意义不在于背下 23 种定义而在于建立一套系统化的软件设计思维——很多人在无意识中已经用过类似思路但只有系统化掌握后才能在复杂场景中主动选择合适的方案。为什么要学设计模式设计模式的核心目标是保证程序的三个特性可扩展性新增需求时不需要大量改动已有代码可维护性代码结构清晰定位和修复问题的成本低可读性其他开发者能快速理解代码意图这三个特性的背后是所有设计模式共同遵循的基本原则。设计模式三大基本原则单一职责原则一个类应该只有一个引起它变化的原因即类的职责要单一。如果一个类同时承担多个不相关的职责这些职责就会耦合在一起——其中一个职责的变化可能影响其他职责的正常工作。后期重构这类万能类需要付出巨大代价尤其是在测试阶段才发现问题时。实践口诀类应该只维护一组相关的属性和行为而不是多组混杂。功能单一的类更容易管理和维护能显著降低 bug 出现概率。开放封闭原则软件实体类、模块、函数应该对扩展开放对修改封闭。这是单一职责原则的延续当类已经专注于单一职责时新需求应该通过扩展新增子类来实现而不是修改已有类。以商场打折系统为例预留一个打折策略接口不同的折扣方式优惠券、买一送一、满减通过子类重写来实现新增折扣策略时不需要改动原有打折逻辑。实现步骤定义包含虚函数的父类如打折策略基类创建子类重写虚函数如优惠券策略“买一送一策略”通过父类指针指向不同子类对象实现运行时多态调用这样做的优势已有类无需修改降低出错风险新增需求只需添加子类可扩展运行时动态绑定灵活。依赖倒转原则高层模块和低层模块都应该依赖抽象层而不是高层依赖低层。高层模块应用程序的顶层业务逻辑低层模块具体功能实现如数据库 API抽象层含虚函数的父类或接口定义通用行为C 实现示例// 抽象层 class Database { public: virtual void connect() 0; virtual void query(const std::string sql) 0; }; // 低层模块MySQL 实现 class MySQL : public Database { public: void connect() override { /* MySQL 连接逻辑 */ } void query(const std::string sql) override { /* MySQL 查询逻辑 */ } }; // 低层模块Oracle 实现 class Oracle : public Database { public: void connect() override { /* Oracle 连接逻辑 */ } void query(const std::string sql) override { /* Oracle 查询逻辑 */ } }; // 高层模块 class Application { private: Database* db; public: Application(Database* db) : db(db) {} void executeQuery(const std::string sql) { db-connect(); db-query(sql); } };设计优势高层模块仅依赖Database抽象类降低耦合新增数据库类型只需继承Database可扩展无需修改高层代码符合开闭原则。补充原则里氏代换子类必须能完全替换父类且不破坏原有逻辑。实现前提继承关系合理子类只扩展父类行为不修改父类已有行为。Qt 中的典型场景void displayWidget(QWidget* widget) { widget-show(); // 可以传入 QDialog、QPushButton 等任意子类 }违反案例——鸭嘴兽问题class Mammal { public: virtual bool isViviparous() { return true; } // 假设哺乳动物都是胎生 }; class Platypus : public Mammal { public: bool isViviparous() override { return false; } // 鸭嘴兽是卵生违反原则 };当Platypus替换Mammal时原有逻辑被破坏。解决方案是重构继承体系移除不普适的约束用更抽象的方式描述class Animal { public: virtual std::string reproductionType() 0; // 更抽象的生殖方式 };多态设计模式的底层机制设计模式的大量灵活性来自 C 的运行时多态其核心是虚函数表。纯虚函数定义接口class AbstractClass { public: virtual void pureVirtual() 0; // 纯虚函数子类必须实现 };需要运行时类型判断时使用dynamic_castDatabase* db new MySQL(); if (auto mysql dynamic_castMySQL*(db)) { // 类型安全的操作 }理解多态机制才能真正理解为什么父类指针指向子类对象能实现如此灵活的扩展。常见模式速览简单工厂模式需要创建多种相似对象时将对象创建逻辑集中到一个工厂类中管理。这是理解更复杂工厂模式的基础建议优先掌握。单例模式确保一个类只有一个实例并提供全局访问点。适用于需要全局唯一对象的场景如配置管理、线程池。属于较简单的创建型模式适合初学者入门。策略模式定义一组算法并分别封装使它们可以互相替换。生活中的类比不同的出行方式步行、公交、自驾都是到达目的地的策略可以根据场景灵活切换。学习建议从简单模式入手初学者优先选择 UML 类图简单的模式单例、简单工厂、适配器建立信心后再深入复杂模式抽象工厂可后置抽象工厂模式复杂度较高适合在有一定代码实践后再学习初学阶段不必强求边学边实践设计模式的理解深度与编程经验正相关建议每学一个模式就写一个小 demo 验证结合已有代码有经验的开发者可以回顾自己写过的代码思考哪些地方可以用设计模式重构设计模式文档常出现每个字都认识但连起来不懂的情况这是正常的——设计模式本质上是对编程经验的抽象总结需要结合实际编码经验才能真正理解。不要追求一次全部掌握先把常用的简单模式用熟复杂模式在实际需要时再深入学习即可。