00-软件系统设计
1. 软件设计
- 需求
- 系统需要满足的目标
- 非规范化的描述
- 规约
- 系统外部可观察到的行为
- 规范化的描述
- 架构
- 系统一级的主要组织部分
- 各部分的交互方式
- 使用的技术
- 设计
- 如何完成任务(算法)
- 需要写的代码
- 关注OO设计
大部分非功能需求都在架构阶段考虑
详细设计关注可维护、可复用
2. 面向对象设计原则概述
- 软件的可维护和可复用
- 好的设计需要具备:
- 可扩展性
- 灵活性
- 可插入性
2.1. 单一职责原则
- 一个对象应该只包含单一职责,并且完整封装在一个类里
- 就一个类而言,应该只有一个引起变化的原因
2.2. 开闭原则
- 对扩展开放,对修改关闭。
- 对可变性封装原则:稳定的中间层把变化的信息封装在模块内部,对外部不可见
- 抽象化是开闭原则的关键
开闭原则是面向对象设计的一个目标
例:抽象类AbstractButton封装了变化,修改或增加子类,LoginForm都不需要变化。
2.3. 里氏代换原则
- 父类支持的性质,子类也必须支持。任何地方用到父类,都可以换成子类。
- 扩展行为可以作为私有函数。重写要保证父类稳定性。
- 错误:子类不能重写父类方法
- 继承要谨慎使用
2.4. 依赖倒置原则
- 抽象不应该依赖细节,细节应该依赖抽象
- 在编程时应该首先定义好抽象层,并尽量保持稳定->开闭原则,抽象层隔绝底层的变化
- 常见实现方式:元数据编程,把抽象放进代码,把细节放进数据
- 面向接口,而不是面向实现编程
2.5. 接口隔离原则
- 客户端不应该依赖那些不需要的接口
- 如果接口太大,就可以分割成更细的接口
例:定制化,使得一些用户无法访问某些方法。控制接口的粒度。
2.6. 合成复用原则
- 尽量使用对象组合,而不是继承
- 我们不希望知道被依赖者的细节,不被被依赖者的变化影响
- 一般和依赖倒置原则一起使用
- 前提/假设:被合成的对象会发生变化
抽象依赖:依赖关系的两侧有一个是抽象的,并且最好是被依赖的
2.7. 迪米特法则/最小知识原则
- 封装
- 每一个软件单位应当尽可能少得与其他实体发生作用
- 为了减少模块之间的影响,扩展更容易
2.7.1. 狭义
狭义:两个类之间不必彼此直接通信,那两个类就不应该发生直接的相互作用
例子:在a对象中需要调用c的功能
- 不遵守迪米特法则:b.getC.getTemp()
- 若B不使用C,则A也需要修改
- 遵守迪米特法则:使用Wrapper Method:, b.getTemp()
- 若B不使用C,而是用其他类,变化对A不可见
- 不遵守迪米特法则:b.getC.getTemp()
- 分析:降低类的耦合,但是造成模块之间通信效率降低(大量Wrapper
2.7.2. 广义
指对对象之间的信息流量、流向以及信息的影响的控制,主要是对信息隐藏的控制
例子:使用控制器封装系统局部的复杂性
在 JDK 中,java.util.Stack是 java.util.Vector类的子类,该设计合理吗?若不合理,请分析解释该设计存在的问题。
违反里氏代换原则,使用Vector的地方不能替换成Stack。
2.8. 封装可变性原则
识别出变化,把变化的部分和不变的部分分离
- 标题: 00-软件系统设计
- 作者: Charlie
- 创建于 : 2024-02-27 14:02:00
- 更新于 : 2024-07-05 12:55:04
- 链接: https://chillcharlie357.github.io/posts/243aaa51/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论