设计模式真的很烂吗:读《Design Patterns Suck》有感
一、偶然读到一篇"离经叛道"的文章今天偶然看到一篇标题很刺眼的文章:"Design Patterns Suck"(设计模式很烂)。作为一个从 C++ 起步、曾经把《设计模式》奉为圭臬的程序员,我带着好奇和一丝抵触点了进去。 文章的观点非常激进: "设计模式被高估了、滥用了,而且常常是完全不必要的。" "设计模式不过是丑陋的变通方案,因为我们的编程语言不够强大、不够灵活,无法表达我们真正想要的东西。" 读完之后,我陷入了沉思。这些话虽然刺耳,但似乎又有点道理。让我从自己的经历出发,谈谈对这个话题的看法。 二、我的设计模式之旅2.1 C++时代的"模式实践"我最早接触设计模式是在大学学习 C++ 的时候。那时候,《设计模式》这本书几乎是每个 C++ 开发者的必备读物。工厂模式、单例模式、观察者模式、策略模式……这些名词像咒语一样被反复念叨。 记得当时做一个简单的学生管理系统,我非要往里塞各种设计模式: 1234567891011121314151617181920212223242...
C++ 语句解析器实战:用注册式工厂打造可扩展语法分析器
在开发脚本引擎或配置解析工具时,我们经常需要处理多种类型的语句(赋值、条件、循环等)。本文将通过一个实用的语句解析器案例,展示如何用注册式工厂模式构建易于扩展的解析系统。 一、需求分析与设计思路我们需要开发一个支持以下语句类型的解析器: 赋值语句(如x = 100) 条件语句(如if x > 5) 循环语句(如for i in 0..10) 核心挑战是:当需要支持新语句类型时,无需修改现有解析逻辑,只需添加新的解析器实现。这正是工厂模式的用武之地。 整体设计方案: 定义抽象解析器接口(基类) 为每种语句实现具体解析器(派生类) 用注册式工厂管理解析器的创建 通过语句特征自动匹配对应的解析器 二、核心代码实现1. 抽象解析器接口首先定义所有解析器的公共接口: 12345678910111213#include <string>// 语句解析器基类class StatementParser {public: virtual ~StatementParser() = default; // 解析语句(提取关键信息)...
C++ 模板工厂模式:从手动注册到自动发现的进化之路
在软件开发中,工厂模式是解耦对象创建与使用的经典方案。但传统工厂模式在面对频繁新增产品时,总会陷入修改工厂类的尴尬。本文将带你探索如何用 C++ 模板实现自动注册的工厂模式,彻底解决这一痛点。 一、传统工厂的 "if-else 地狱"假设我们要开发一个支持多种日志输出的组件(控制台日志、文件日志、网络日志),传统工厂实现可能是这样的: 123456789101112131415161718class Logger {public: virtual void log(const std::string& msg) = 0; virtual ~Logger() = default;};class ConsoleLogger : public Logger { /* 实现 */ };class FileLogger : public Logger { /* 实现 */ };class LoggerFactory {public: static std::unique_pt...
责任链模式
一、责任链模式原理说明1.1 模式定义根据《大话设计模式》定义,责任链模式(Chain of Responsibility Pattern) 是一种对象行为型模式,它使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 1.2 模式结构责任链模式包含以下核心角色,各角色职责明确且协同工作: 角色名称 核心职责 典型实现方式 抽象处理者(Handler) 定义处理请求的接口,包含抽象处理方法和一个后继连接 抽象类或纯虚函数接口 具体处理者(ConcreteHandler) 实现抽象处理者的接口,判断能否处理当前请求;若能则处理,否则将请求转发给后继者 继承抽象处理者的具体类 客户端(Client) 创建处理链,并向链头的具体处理者提交请求,不关心请求的处理细节和传递过程 主函数或业务逻辑模块 1.3 工作流程客户端创建多个具体处理者对象,按照业务逻辑顺序构建责任链(设置每个处理者的后继者) 客户端将请求发送给责任链的第一个处理者 第一个处理者判断自身是否能处理该请求:...
观察者模式
一、模式核心原理1.1 模式定义观察者模式(Observer Pattern)是一种行为型设计模式,定义了对象间一对多的依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会自动收到通知并更新。 该模式的核心价值在于解耦被观察者与观察者: 被观察者无需知道具体观察者的类型和实现 观察者可独立添加 / 移除,不影响被观察者核心逻辑 支持事件驱动架构的灵活扩展 1.2 UML 类图结构观察者模式包含四个核心角色: 角色 职责 典型实现 Subject(抽象被观察者) 定义观察者管理接口(注册 / 移除 / 通知) 抽象基类 ConcreteSubject(具体被观察者) 维护状态,状态变化时通知所有观察者 继承 Subject 的具体类 Observer(抽象观察者) 定义更新接口,供被观察者通知时调用 抽象基类 ConcreteObserver(具体观察者) 实现更新接口,处理被观察者的通知 继承 Observer 的具体类 12345678910111213141516+-------...
抽象工厂模式
一、工厂方法模式的局限性工厂方法模式仅能创建单一产品等级结构的对象,当系统需要创建多个相互关联的产品族时,工厂方法模式便显现出明显不足。例如,在开发跨平台 UI 组件时,需要同时创建 Windows 风格的按钮和文本框,以及 macOS 风格的按钮和文本框,这些按钮和文本框分别构成不同的产品族。若使用工厂方法模式,需为每个产品(按钮、文本框)都创建对应的工厂类,会导致类的数量急剧增加,且难以保证同一产品族内产品的一致性。而抽象工厂模式恰好能解决这一问题,它可提供一个接口,用于创建一系列相关或相互依赖的对象,无需指定它们的具体类。 二、抽象工厂模式结构2.1 结构文字描述抽象工厂模式包含四个核心角色: 抽象工厂(Abstract Factory):声明一组用于创建一族产品的方法,每个方法对应一种产品。 具体工厂(Concrete Factory):实现抽象工厂中声明的创建产品的方法,生成具体的产品对象,一个具体工厂对应一个产品族。 抽象产品(Abstract Product):为每种产品声明接口,定义产品的公共方法。 具体产品(Concrete Product):实现抽象产...
C++ 类间关系与功能复用
导言在面向对象编程的世界里,类与类之间的关系设计和功能复用机制是构建高质量软件的基石。理解这些概念不仅有助于写出结构清晰的代码,更能提升系统的可维护性和扩展性。本文将结合实例,深入探讨 C++ 中类间的五大关系(继承、组合、聚合、关联、依赖),并分享对功能复用的理解与实践经验。 一、对类间关系的本质理解类间关系本质上反映了现实世界中事物之间的联系,是对客观世界的抽象。在面向对象设计中,我们通过类间关系来建模这些联系,使软件系统更贴近现实逻辑。 类间关系并非孤立存在,它们之间存在着从强耦合到弱耦合的渐变过程:继承 > 组合 > 聚合 > 关联 > 依赖。这种耦合度的差异,决定了它们在不同场景下的适用性。 让我们以基础类 A 为核心,通过具体代码来理解这些关系: 123456789class A{public: friend class E; void func() { cout << "hello,world" << endl; }}; ...
策略模式的实践与解析
一、核心概念1.1 定义策略模式(Strategy Pattern)核心思想是将算法家族封装起来,使它们之间可以相互替换,且算法的变化不会影响使用算法的客户端。该模式通过面向对象的多态机制,实现了算法与使用环境的解耦,让代码结构更清晰、可维护性更强。 1.2 核心解决的问题在传统开发中,若一个功能存在多种实现算法(如排序算法、支付方式、日志记录方式),通常会使用if-else或switch语句进行分支判断,选择不同的算法实现。这种方式存在以下问题: 代码耦合度高:算法逻辑与调用逻辑混杂在同一代码块中 扩展性差:新增算法需修改原有判断逻辑,违反开闭原则 维护成本高:算法逻辑分散,后续修改易引发连锁反应 可读性差:大量分支判断导致代码逻辑复杂,难以理解 策略模式通过将不同算法封装为独立的策略类,彻底解决了上述问题,使代码结构更符合面向对象设计原则。 二、结构组成策略模式包含三个核心角色,各角色职责明确,协同工作实现算法的灵活切换: 2.1 抽象策略类(Strategy) 职责:定义所有具体策略类的公共接口,声明算法的核心方法 形式:通常以纯虚基类(抽象类)实现,确保所有...
C++ 装饰模式
一、模式定义与核心思想装饰模式(Decorator Pattern)是结构型设计模式的重要成员,核心思想是:通过组合而非继承的方式,动态为对象添加额外职责。它避免了继承体系的臃肿,允许灵活组合多个功能,实现 “即插即用” 的扩展效果。 关键特征: 装饰器与被装饰对象遵循同一接口(或继承同一基类) 装饰器持有被装饰对象的引用,实现功能叠加 支持多层装饰,形成职责链 二、UML 类图结构1234567891011121314151617181920+----------------+| 抽象组件(Component) |+----------------+| + operation() |+----------------+ ↑ |+----------------+ +----------------+| 具体组件(Concrete) | | 装饰器基类(Decorator) |+----------------+ +----------------+| + operation() | | -...
C++ 工厂方法模式
一、模式简介工厂方法模式(Factory Method Pattern)是创建型设计模式的核心成员,其核心思想是:定义一个创建对象的接口(抽象工厂),但由子类(具体工厂)决定实例化哪个类(具体产品)。通过这种设计,将对象的创建逻辑与使用逻辑彻底分离,让代码更具扩展性和可维护性。 二、核心概念与结构工厂方法模式包含 4 个关键角色,形成清晰的继承体系: 抽象产品(Abstract Product) 定义产品的通用接口,所有具体产品都需实现该接口。例如 “交通工具” 抽象类,包含 “行驶” 纯虚函数。 具体产品(Concrete Product) 抽象产品的实现类,是工厂方法最终创建的对象。例如 “汽车”“自行车” 类,分别实现 “行驶” 方法。 抽象工厂(Abstract Factory) 定义创建产品的接口(工厂方法),返回抽象产品类型。例如 “交通工具工厂” 抽象类,包含 “创建交通工具” 纯虚函数。 具体工厂(Concrete Factory) 抽象工厂的实现类,重写工厂方法,返回具体产品实例。例如 “汽车工厂” 创建汽车对象,“自行车工厂” 创建自行车对象。 三、代码示例1...
C++ 实现简单工厂模式
一、简单工厂简单工厂模式的核心是通过一个工厂类统一创建不同产品实例,本质是将对象创建逻辑与使用逻辑分离。C++ 作为面向对象编程语言,天然支持类与继承、多态、虚函数等特性,相比 C 语言的模拟实现,能更直接、优雅地满足简单工厂模式的设计意图,且无需手动管理函数指针与内存分配的绑定关系。 从两个维度理解适配性: 语法维度:通过抽象基类定义产品接口,具体产品类继承基类并实现纯虚函数,工厂类通过静态成员函数创建产品实例,完全符合面向对象的设计规范 功能维度:利用 C++ 的多态特性,调用者可通过基类指针 / 引用统一操作不同产品,无需关注具体产品类型;通过构造函数与析构函数自动管理内存,避免内存泄漏风险 二、核心结构2.1 核心角色定义(面向对象原生支持) 角色名称 实现方式 核心职责 抽象产品(Product) 抽象基类(含纯虚函数) 定义所有产品的统一接口,规范产品行为 具体产品(ConcreteProduct) 继承抽象基类的子类 实现抽象产品的纯虚函数,提供具体产品的业务逻辑 工厂(Factory) 包含静态成员函数的类 根据输入参数(如类型枚举、字...
类图设计--编程的前置准备
一、类图设计方法论:构建稳健的面向对象模型类图建模的本质是将现实世界的业务概念转化为计算机可理解的面向对象结构。遵循科学的方法论是确保模型质量的基础,核心包含四大环节:元素识别、关系构建、属性定义与模型优化。 1.1 元素识别:精准定位核心建模单元元素识别是类图设计的起点,需从业务需求中提取关键概念并转化为 UML 元素。识别过程需遵循 "单一职责原则",确保每个元素职责清晰、边界明确。 核心元素类型及识别方法 元素类型 识别特征 表示符号 应用场景 类 (Class) 具有相同属性和行为的对象集合 矩形(分三层:类名 / 属性 / 方法) 业务实体(如 User、Order)、控制逻辑(如 OrderService)、工具组件(如 DateUtils) 接口 (Interface) 定义行为契约,无具体实现 棒棒糖形状或矩形(标注 <>) 服务契约(如 PaymentGateway)、模块边界(如 UserRepository) 抽象类 (Abstract Class) 不能实例化,包含抽象方法 类名斜体或标...
基于图形面积计算项目的 OOA/OOD/OOP 全流程解析与类图设计
一、面向对象分析(OOA):需求提取与实体识别1.1 核心业务需求本系统旨在实现以下关键功能: 支持对多种基础几何图形,包括矩形、圆形和三角形的面积计算; 以统一的方式展示不同类型图形的名称及其对应的面积计算结果; 构建具有高度扩展性的系统架构,确保在新增图形类型时,现有计算逻辑无需进行任何修改。 1.2 核心实体识别(3 个以上核心实体)经过严谨的需求分析,本研究确定了以下核心业务实体,并对各实体的属性、行为及业务约束进行了详细定义: 实体名称 核心属性 核心行为 业务约束 图形(Figure) 无直接属性(抽象概念) 获取名称、计算面积 作为抽象基类,不可实例化,需由具体图形类继承 矩形(Rectangle) 长度(length)、宽度(width) 计算面积、返回名称 长度和宽度必须为正数 圆形(Circle) 半径(radius) 计算面积、返回名称 半径必须为正数 三角形(Triangle) 三边长度(a、b、c) 计算面积、返回名称 三边长度需满足三角不等式(a+b>c 等) 图形管理器(FigureManager) 图形集...
C++ 静态成员与单例模式:从基础到线程安全实现
一、静态成员的本质与特性1.1 静态数据成员:类级别的共享状态静态数据成员不属于任何对象实例,而是属于整个类,其内存空间在程序生命周期内唯一存在。 123456789101112131415161718192021222324252627#include <iostream>class Counter {private: // 静态数据成员声明:类内声明,类外定义 static int s_totalInstances; int m_id; // 非静态成员:每个对象拥有独立副本public: Counter() { m_id = ++s_totalInstances; // 每次创建对象自增计数 } int getId() const { return m_id; } static int getTotalInstances() { return s_totalInstances; }};// 静态数据成员必须在类外定义(C++17...

