当前位置: 首页 > news >正文

【读书笔记】《C++ Software Design》第二章:The Art of Building Abstractions

《C++ Software Design》第二章:The Art of Building Abstractions

本章详细探讨如何在 C++ 中构建高质量的抽象,包括行为预期、一致性、所有权管理和文档化。

Guideline 6: Adhere to the Expected Behavior of Abstractions

6.1 An Example of Violating Expectations

  • 示例场景:实现一个 Stack<T> 类时,提供 pop() 方法返回 T&,但在空栈调用时未抛出异常,而是返回未定义引用。

  • 问题:客户端无法预期 pop() 行为,违反直觉。

  • 解决方案

    • 改用 std::optional<T> 返回值,或抛出明确异常 std::underflow_error
    • 添加文档注释,明确表明函数的异常保证级别(noexcept 语义)。

6.2 The Liskov Substitution Principle

  • 定义:子类型必须能够替换父类型且不改变程序语义。

  • 具体实践

    • 前置条件:子类方法不应要求更严格输入。

    • 后置条件:子类方法输出应满足基类声明的约定。

    • 示例

      struct IShape { virtual double area() const = 0; };
      struct Rectangle : IShape { double area() const override; };
      struct Square : Rectangle { double side; double area() const override { return side * side; } };
      
    • 确保 Square 中不破坏 Rectangle 的预期行为,如修改 side 时边长一致性。

6.3 Criticism of the Liskov Substitution Principle

  • 争议:严格遵循 LSP 可能导致复杂的类型层次和过度抽象。
  • 作者观点:注重抽象的语义契约即可,不必机械化实施所有 LSP 条件。
  • 实践建议:编写契约测试(Contract Tests)验证继承层次的行为一致性。

6.4 The Need for Good and Meaningful Abstractions

  • 要点:抽象应贴合领域概念,避免陷入技术细节。

  • 示例:定义 Money 类型:

    class Money {long cents;
    public:explicit Money(long c): cents(c) {}double as_dollars() const { return cents / 100.0; }
    };
    
  • 好处:减少单元转换错误,增强类型安全性与可读性。

Guideline 7: Understand the Similarities Between Base Classes and Concepts

  • 继承与概念:两者均定义范畴与行为规范。

  • 运行时 vs 编译时:继承多态在运行时决议;概念约束在编译时检查。

  • 示例对比

    // 继承多态
    struct IFoo { virtual void foo() = 0; };
    void callFoo(IFoo* f) { f->foo(); }// 概念约束
    template<typename T>
    concept Fooable = requires(T a) { a.foo(); };
    void callFoo(Fooable auto& f) { f.foo(); }
    
  • 实践:对性能敏感场景优先使用概念,需动态扩展场景使用继承。

Guideline 8: Understand the Semantic Requirements of Overload Sets

8.1 The Power of Free Functions: A Compile-Time Abstraction Mechanism

  • 优势:支持对第三方类型扩展接口,无需修改原始类。

  • 示例

    struct Vector2D { float x, y; };
    inline float length(const Vector2D& v) { return std::hypot(v.x, v.y); }
    

8.2 The Problem of Free Functions: Expectations on the Behavior

  • 契约:自由函数应与成员函数语义一致。

  • 示例std::data(), std::size() 应返回与成员函数相同结果。

  • 实践

    • 在头文件中使用 using std::data; 保证 ADL 正常。
    • 文档明确输出和异常语义。

Guideline 9: Pay Attention to the Ownership of Abstractions

9.1 The Dependency Inversion Principle

  • 实践示例

    struct ILogger { virtual void log(std::string_view) = 0; };
    class ConsoleLogger : public ILogger { void log(std::string_view msg) override { std::cout<<msg; } };
    class App { std::unique_ptr<ILogger> logger; };
    

9.2 Dependency Inversion in a Plug-In Architecture

  • 步骤

    1. 定义插件接口 IPlugin
    2. 插件库导出 createPlugin() C 接口。
    3. 主程序用 dlopen/dlsym 加载并注册。
  • 代码

    extern "C" IPlugin* createPlugin();
    

9.3 Dependency Inversion via Templates

  • 示例

    template<typename Logger>
    class App { Logger logger; };
    

9.4 Dependency Inversion via Overload Sets

  • 示例

    void save(Data& d) { d.save(); }  // 自由函数调用 d.save()
    

9.5 DIP vs SRP

  • DIP:管理高低层依赖。
  • SRP:管理类职责。
  • 结合:通过细粒度接口同时满足二者。

Guideline 10: Consider Creating an Architectural Document

  • 目的:提升团队对系统全貌的理解。

  • 建议文档

    • 组件图(Component Diagram)
    • 类图(Class/Concept Diagram)
    • 序列图(Sequence Diagram)
    • 数据流图(Data Flow Diagram)
  • 工具:PlantUML、Mermaid。

  • 实践:将 UML 源文件纳入版本控制,与代码同步迭代。

http://www.lryc.cn/news/586144.html

相关文章:

  • 使用python 实现一个http server
  • Elasticsearch 线程池
  • MIG_IP核的时钟系统
  • 使用 Java 开发大数据应用:Hadoop 与 Java API 的结合
  • Linux中使用快捷方式加速SSH访问
  • 让 VSCode 调试器像 PyCharm 一样显示 Tensor Shape、变量形状、变量长度、维度信息
  • 细解muduo中的每个核心类
  • pytorch深度学习—RNN-循环神经网络
  • 关于wpf的自适应
  • vue2和vue3的响应式原理
  • Java中的内存溢出详解
  • 【Python练习】039. 编写一个函数,反转一个单链表
  • Linux系统使用Verdaccio搭建Npm私服
  • 初学者关于算法复杂度的学习笔记
  • python数据分析及可视化课程介绍(01)以及统计学的应用、介绍、分类、基本概念及描述性统计
  • 【Datawhale AI 夏令营】 用AI做带货视频评论分析(二)
  • 使用Java完成下面程序
  • 13. https 是绝对安全的吗
  • Spring AOP 是如何生效的(入口源码级解析)?
  • 基于Java的Markdown到Word文档转换工具的实现
  • 码头智能哨兵:AI入侵检测系统如何终结废钢盗窃困局
  • DirectX Repair修复工具下载,.NET修复,DirectX修复
  • 贪心算法题解——跳跃游戏 II【LeetCode】
  • 电商订单数据分析全流程:从数据处理到可视化洞察
  • AI产品经理面试宝典第11天:传统软件流程解析与AI产品创新对比面试题与答法
  • 网络连接:拨号连接宽带PPPOE
  • 维基艺术图片: python + scrapy 爬取图片
  • 物联网设备数据驱动3D模型的智能分析与预测系统
  • 深入理解 QSettings:Qt 中的应用程序配置管理
  • 多线程的区别和联系