软件构造第六章复习总结

本文围绕软件可维护性展开,介绍了继承深度、类耦合、单元测试覆盖率等常用可维护性指标,阐述了SOLID面向对象编程原则,还讲解了工厂方法、抽象工厂等多种设计模式,以及语法、正则表达式相关知识,强调记住正则用法和SOLID原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在软件发布后,修改软件以修正错误 和提升性能
一些常用的可维护性指标
继承深度 - 表示扩展到类层次结构根的类定义的数量。 层次越深,理解特定方法和字段的定义或/和重新定义的难度就越大。
▪类耦合 - 通过参数,局部变量,返回类型,方法调用,通用或模板实例化,基类,接口实现,在外部类型上定义的字段以及属性修饰来测量与唯一类的耦合。

  • 良好的软件设计要求类型和方法应具有高内聚力和低耦合性。
  • 高耦合表明设计难以重用和维护,因为它与其他类型有很多相互依赖性。
    ▪单元测试覆盖率 - 指示自动单元测试涵盖代码库的哪个部分
    Five Rules of Modularity Design

Direct Mapping (直接映射) ▪ Few Interfaces (尽可能少的接口) ▪ Small Interfaces (尽可能小的接口) ▪ Explicit Interfaces (显式接口) ▪ Information Hiding (信息隐藏)

耦合是模块之间依赖性的度量。 如果一个模块中的更改可能需要更改另一个模块,则两个模块之间存在依赖关系。
决定于 接口数量 接口复杂度,通讯的复杂度
凝聚力衡量模块的功能或职责的相关程度。 ▪如果模块的所有元素都朝着相同的目标努力,则模块具有高内聚力。
SOLID 面向对象编程原则
▪ (SRP) The Single Responsibility Principle 单一责任原则
引起类变化的原因只有一个,专心做一件事

▪ (OCP) The Open-Closed Principle 开放封闭原则
对扩展是开放的 ,对修改是封闭的,应通过继承和组合改变/扩展功能
当软件系统必须支持一组替代方案时,系统中应该有且只有一个 模块知道方案的详尽列表。
当需要变化时,通过扩展隐藏在接口之后的子类加以完成,而不要修 改接口本身。
▪ (LSP) The Liskov Substitution Principle Liskov替换原则
使用指针或对基类的引用的函数必须能够使用派生类的对象而不知道它”,即子类在用于代替其基类时应该表现得很好(关注的是“操作”的可替换性)
子类型必 须能够替换其基类型)
LSP:对外界看来,父类和子类是“一样”的;

▪ (ISP) The Interface Segregation Principle 接口隔离原则
“客户不应该被迫依赖他们 不使用的接口”,即保持小接口。
– DIP:对接口编程,而不是对实现编程,通过抽象接口隔离变化;

▪ (DIP) The Dependency Inversion Principle 依赖转置原则
高层模块不应该依赖于低层 模块,二者都应该依赖于抽象。
抽象不应该依赖于实现细节,实现细节应该依赖于抽象。
类的契约形式化 通过前置和后置条件, 清晰定义子程序的功能
形成测试友好的设计

抽象(abstraction):模块之间通过抽象隔离开来,将稳定部分和容易 变化部分分开

分离(Separation): Keep It Simple, Stupid (KISS) – SRP:按责任将大类拆分为多个小类,每个类完成单一职责,规避变化,提 高复用度; – ISP:将接口拆分为多个小接口,规避不必要的耦合
归纳起来:让类保持责任单一、接口稳定。

GRASP patterns

一般责任分配软件模式(原则),缩写为GRASP,包含为OOP中的类和对象分配责任的准则。Controller
将系统输入事件处理由统一的外观控制器类负责,某个用例的场景控制由用例控 制器负责。
控制器类本身负责收发工作,具体执行通过委托机制进行指派
拥有信息的类负责相应的责任。
Creator
Low Coupling
High Cohesion
Indirection. 将责任 分配给中间对象,以避免直接耦合
Polymorphism根据多态性原则,基于类型定义行为变化的责任被分配给发生这种变化的类型。
Protected variations 防止变异
Pure fabrication 纯虚构e. 设 计虚构的类实现高内聚低耦合和复用
接下来我们看一下设计模式
Factory Method pattern
Static Factory Method静态工厂方法
有名字,易于理解。 通过定义工厂父类负责定义创建对象的公共接口,而工 厂子类则负责生成具体的对象
当一个类不知道它所 需要的对象的类时。在工厂方法模式中,客户端不需要知道具体产品类的 类名,只需要知道所对应的工厂即可。
当一个类希望通过 其子类来指定创建对象时。在工厂方法模式中,对于抽象工厂类只需要提 供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向 对象的多态性和Liskov原则,在程序运行时,子类对象将覆盖父类对象, 从而使得系统更容易扩展。
.将创建对象 的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是 哪一个工厂子类创建产品子类,需要时再动态指定。

Abstract Factory Pattern
提供一个创建一系列相关或相互依赖对象的接口,而 无需指定它们具体的类
使用工厂返回可用于创建相关对象集的 工厂。
抽象工厂模式是对工 厂模式的扩展,允许一个工厂创建更多类型的对象(或者组合更多的对 象构成产品),而工厂模式中一个对象只允许创建一个对象。
一个系统要独立于它的产品的创建、组合 和表示时。 一个系统要由多个产品系列中的一个来配置时。 .当你要强调一系列相关的产品对象 的设计以便进行联合使用时。 当你提供一个产品类库, 而只想显示它们的接口而不是实现时,所有产品以同样的接口出现 ,客户端不需要依赖具体实现。

Builder Pattern
将复杂对象的构造与其表示分开,以便相同 的构建过程可以创建不同的表示
构造算法由单个类(“director”)指定

  • 算法的抽象步骤(每个部分一个)由接口(“builder”)指定
  • 每个表示提供接口的具体实现( “concrete builders”)
  • 在这里插入图片描述

Abstract Factory 专注于产品族的构建 构建过程客户端可见
Builder 构建过程复杂 复杂产 品的构建会不时变化构建过程客户端不可见
二者可以结合完成复杂产品族的构建
Bridge Pattern
将抽象概念与实 现分离,避免过于复杂的继承结构
将类的功能层次结构(abstract)与实现层次结构分离(implementation)
面向客户的逻辑继承结构 面向实现的物理继承结构
在这里插入图片描述

Proxy Pattern Motivation
避免对象被客 户端直接访问
远程代理:为 一 个 对 象在 不 同 的 地 址 空间 提 供 局 部 代 表 (缓存机制)
虚代理:根 据需要创建开销很大的对象
保护代理 提供访问保护
Composite Pattern 组合模式
容器中具有基本元素和组合元素两类,如何以统一的方式访问所有的元素
递归方式访问
Observer pattern
观察模式 一种“发布-订阅”形式,发布方的变化,会
通知订阅方
订阅方在发布方 注册 通过 接口分离两者
Abstract subject: maintain list of dependents; notifies them when master changes (the publishers) 维护订阅者列表
Abstract observer: define protocol for updating dependents (the subscribers) 定义更新的协议
Concrete subject: manage data for dependents; notifies them when master changes 维护数据,修改后通知订阅者
Concrete observers: get new subject state upon receiving update message 得到通知后,修改自身的状态
Mediator Pattern
中介模式
中 介者模式中,参与者之间区分不明显(既可以是发送者,也可以是接收者) ,通过mediator作为集中式的hub进行通讯。
r. 观察 者模式中,信息的发送者和接收者划分明确,接收者主要接收发送者发送 的通知和数据。
Visitor Pattern
将数据结构与其上的处理分离
当操作逻辑发生变化时,只需要修改visitor的实现,而不需要修改类。
在多个对象间逐一 传递请求,直到有能够处理的对象执行。
Command Pattern
将请求封装为对象,进而可用不同的请求对客户端进行参数化处 理,对请求进行排队、记录请求日志、支持可撤销的操作。
有时必须向某对象提交请求,但并不知道关于被请求的操作 或请求的接受者的任何信息。
工具箱的设计者无法知道请求的接受 者或执行的操作 ,只有使用工具箱的应用知道该由哪个对象做哪个操作
命令模式通过将请求本身变成一个对象来使工具箱对象可向未指定的应用对 象提出请求。这个对象可被存储并像其他的对象一样被传递。
复合,适配器,桥梁,外墙,代理(结构模式) - 重点:组合对象以形成更大的结构•从旧功能实现新功能,•提供灵活性和可扩展性
▪命令,观察者,策略,模板(行为模式) - 重点: 算法和对象责任的分配•避免与特定解决方案的紧密耦合
▪抽象工厂,构建器(创建模式) - 焦点:创建复杂对象•隐藏复杂对象的创建和组合方式
模块的输入/输出,在内存中存储时为 “串”,在模块间交互时为“流”
语法用于判断合法性,及将字符/字节序列解析为特定数据结构
正则表达 式用于处理字符串,进行拆分、信息提取和转换
解析器生成器根据语法 生成解析器,解析器用于解析字符串

语法中的文字字符串称为终端。终结符/终止符 - 它们被称为终端,因为它们是表示字符串结构的解析树的叶子。 - 他们没有任何孩子,也无法进一步扩展。 - 我们通常用引号编写终端,比如’http’或’:’。
语法由一组产品(产生式)描述,其中每个产品定义非终结符(非终结符)。 - 非终结符就像一个代表一组字符串的变量,而生成作为该变量的定义,就其他变量(非终结符号),运算符和常量(终端)而言。 - 非终结符是表示字符串的树的内部节点
连接(连接),不是由符号表示,而是仅用空格表示:x :: = yz,x是一个y后跟一个z

  • 重复(重复),由*表示:x :: = y * x是0或 更多y
  • Union(合并),也称为交替,由|:x :: = y |z表示 x或y或z
    Optional (0 or 1 occurrence), represented by ?: x ::= y?
    an x is a y or is the empty string
    – 1 or more occurrences:represented by +: x ::= y+ an x is one or more y (equivalent to x ::= y y* )
    – A character class […], representing the length-1 strings containing any of the characters listed in the square brackets: x ::= [abc] is equivalent to x ::= ‘a’ | ‘b’ | 'c‘
    – An inverted character class [^…], representing the length-1 strings containing any character not listed in the brackets: x ::= [^abc] is equivalent to x ::= ‘d’ | ‘e’ | ‘f’ | … (all other characters in Unicode)
    按照惯例,后缀运算符* ,?和+具有最高优先级,这意味着它们首先应用。
    ▪接下来应用连接。
    ▪轮换| 具有最低优先级,这意味着它最后应用。
    树的叶子是已经解析的字符串的部分。
  • 将叶子连接在一起,我们将恢复原始字符串。
  • 主机名和单词nonterminals是树的节点,其树的子树与语法中的规则匹配。
  • 主机名等非终结节点的直接子节点遵循主机名规则的模式,单词“。” 字

Markdown一种可以使用普通文本编辑器编写的标记语言,通过简单的标 记语法,它可以使普通文本内容具有一定的格式

对root对应的产生式 右侧,替换其中所有root之外的非终结符(用非终结符的右侧),如果最 终可以得到只有终结符和操作符构成的产生式,则为正则语法
为简单起见,我们假设格式分隔符之间的纯文本不允许使用任何格式标点符号,如_或<。

。 任何单个字符
▪\ d任何数字,与[0-9]相同
▪\ s任何空白字符,包括空格,制表符,换行符
▪\ w任何单词字符,包括字母和数字
▪\。,\(,\), \ *,\ +,…反斜杠转义一个运算符或特殊字符,以便它按字面意思匹配

上下文无关文法左侧只含有一个 非终结符,它定义的语法范畴(或语法单位)是完全独立于这种范畴 可能出现的环境,无需考虑上下文。
不是所有CFG都是正 则的。
程序设计语言的语法多数都是CFG
解析器接受一系列字符并尝试将序列与语法匹配。
▪解析器通常会生成一个解析树,它显示语法产生如何扩展为与字符序列匹配的句子。

  • 解析树的根是语法的起始非终结符号。
  • 解析树的每个节点都扩展为一个语法生成。
    ▪表示语言表达式的递归抽象数据类型称为抽象语法树(AST)。
    Grammar定义语法规则,Parser generator根据grammar定义的规则 产生一个parser,client利用parser来解析文本,看其是否符合语法定 义并对其做各种处理(例如转成parse tree)
    解析器设计模式允许将规则定义为类
    . 适用于简单 语法情况,此模式不采用AST的方式解析表达式,节省空间和时间。
    State pattern
    允许在运行时修改对象的行为和状态,每个行为用一个状态 类表达
    状态对象不包含任何属性 修改状态时,修改state object 具体执行的方法,委托给状态对象
    Memento Pattern 备忘录模式
    .在不破坏 封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状 态。需要的时候,可以恢复到保存的状态。
    Table-driven construction
    使用表来查询信息而不是使用复杂逻辑语句的模式
    以上为第六章的内容,主要讲解了可维护性的常见度量指标 ▪ 聚合度与耦合度 ▪ SOLID ▪ 设计模式:factory method、 abstract factory、builder、 bridge、proxy、composite、 observer/observable、visitor、 state、memento ▪ 语法、正则表达式 ,主要记住正则表达式的用法,还有solid的设计原则。
基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值