C++20高级编程 第六章 设计可重用代码

发布时间 2024-01-05 15:57:53作者: Mesonoxian

第六章 设计可重用代码


重用哲学

  • 编写一次,经常使用
  • 不惜一切代价避免代码重复
  • DRY(Don't Repeat Yourself)
    (不要重写自己写过的代码)
  • 代码不大可能只在一个程序中使用
    (因而应该正确设计好接口与结构)
  • 团队中其他程序员必须也能使用你的代码

"客户"一般指使用接口的程序员,"用户"一般指使用程序者

C++设计两个原则

  • 抽象: 设计函数与类,使得自己和其他程序员可以通过接口使用它们,而不需要知道底层实现.
  • 重用: 编写适合重用的代码,一次编写,多次使用.

库: 是用于完成特定任务或者针对特定领域的代码集合.

框架: 是代码的集合,围绕框架设计程序.例如,微软基础类(Microsoft Foundation Classes,MFC)与Qt

API: 应用程序编程接口,为库或代码为特殊目的提供的接口.

原型: 首次使用某个新库或框架时为了测试库功能与性能的程序.

使用抽象

抽象 的关键是有效地将接口与实现分离.

实现是用来完成任务的代码,接口是其他用户使用代码的方式.

一个好的接口应该只包含公共方法.

类的属性永远不应该公开,但是可以通过获取器与设置器公开.

当设计接口时,不要向客户公开实现细节.

有时为了将某个接口返回的信息传递给其他接口,库要求客户代码保存这些信息.

这一信息有时被称为 句柄 ,用来跟踪某些特别的实例.

构建重用代码的规则

  • 避免组合不相干的概念或者逻辑上独立的概念(高内聚)
  • 将程序分为逻辑子系统(低耦合)
  • 用类层级结构分离逻辑概念
  • 用聚合分离逻辑概念
  • 消除用户界面依赖

系统设计步骤

  • 将系统分割为子系统

模型-视图-控制(MVC)模式:许多应用程序经常要处理一组数据,处理这些数据上的一个或多个视图,并操作这些数据.

子系统相关表格示例
子系统 实例数 功能 公开的接口 使用的接口
GamePlay 1 开始游戏
控制游戏进度
控制绘图
控制胜方
结束游戏
游戏结束 轮流(Play提供)
绘图(ChessBoardView提供)
ChessPieceView 32 移动自身
检测合法移动
移动
检测移动
获取棋子(ChessBoard提供)
移动棋子(ChessBoard提供)
... ... ... ... ...

alt MVC三个组件间关系

alt 线程通信图

  • 选择线程模型

  • 指定每个子系统的类层次结构

alt UML类层次结构

  • 指定每个子系统的类,数据结构,算法和模式
子系统 数据结构 算法 模式
GamePlay GamePlay类 GamePlay对象包含
一个ChessBoard对象
和两个Player对象
让每个玩家轮流移动
ChessPiece 抽象超类:ChessPiece
子类:
Rook,Bishop,Knight
King,Pawn,Queen
每个棋子存储它在
棋盘上的位置
在棋盘的不同位置查询棋子,
判断棋子的移动是否合法
... ... ... ... ...

开源库

开源运动的两个术语: 自由软件(free software)开放源代码软件(open-source software)

开源库资源来源:

alt UML序列图

设计合理接口

  • 应用程序编程接口(API)
  • 工具类或者库
  • 子系统接口
  • 组件接口

SOLID原则

  • SRP(Single Responsiblity Principle):单一责任原则,设计组件时,应该关注单个任务或者一组任务,"高内聚".
  • OCP(Open/Closed Principle):开放/关闭原则,设计的类应当具有扩展性,其行为应当是可拓展的.
  • LSP(Liskov Substitution Priciple):里氏替换原则,对于一个对象而言,应当能使用该对象的子类型替代该对象的实例.
  • ISP(Interface Segregation Principle):接口隔离原则,为了在提供足够功能的同时降低复杂性,可提供两个独立接口.
  • DIP(Dependency Inversion Principle):依赖倒置原则,使用接口倒置依赖关系.