00-软件系统设计

Charlie

1. 软件设计

  1. 需求
    • 系统需要满足的目标
    • 非规范化的描述
  2. 规约
    • 系统外部可观察到的行为
    • 规范化的描述
  3. 架构
    • 系统一级的主要组织部分
    • 各部分的交互方式
    • 使用的技术
  4. 设计
    • 如何完成任务(算法)
    • 需要写的代码
    • 关注OO设计

大部分非功能需求都在架构阶段考虑
详细设计关注可维护、可复用

2. 面向对象设计原则概述

  • 软件的可维护和可复用
  • 好的设计需要具备:
    • 可扩展性
    • 灵活性
    • 可插入性

2.1. 单一职责原则

  • 一个对象应该只包含单一职责,并且完整封装在一个类里
    • 就一个类而言,应该只有一个引起变化的原因

2.2. 开闭原则

  • 对扩展开放,对修改关闭。
    • 对可变性封装原则:稳定的中间层把变化的信息封装在模块内部,对外部不可见
    • 抽象化是开闭原则的关键

开闭原则是面向对象设计的一个目标

例:抽象类AbstractButton封装了变化,修改或增加子类,LoginForm都不需要变化。
image.png

2.3. 里氏代换原则

  • 父类支持的性质,子类也必须支持。任何地方用到父类,都可以换成子类。
    • 扩展行为可以作为私有函数。重现要保证父类稳定性。
    • 错误:子类不能重写父类方法
  • 继承要谨慎使用

2.4. 依赖倒置原则

  • 抽象不应该依赖细节,细节应该依赖抽象
    • 在编程时应该首先定义好抽象层,并尽量保持稳定->开闭原则,抽象层隔绝底层的变化
  • 常见实现方式:元数据编程,把抽象放进代码,把细节放进数据
  • 面向接口,而不是面向实现编程

image.png

2.5. 接口隔离原则

  • 客户端不应该依赖那些不需要的接口
    • 如果接口太大,就可以分割成更细的接口

例:定制化,使得一些用户无法访问某些方法。控制接口的粒度。
image.png
image.png

2.6. 合成复用原则

  • 尽量使用对象组合,而不是继承
    • 我们不希望知道被依赖者的细节,不被被依赖者的变化影响
    • 一般和依赖倒置原则一起使用
  • 前提/假设:被合成的对象会发生变化

抽象依赖:依赖关系的两侧有一个是抽象的,并且最好是被依赖的

2.7. 迪米特法则/最小知识原则

  • 封装
  • 每一个软件单位应当尽可能少得与其他实体发生作用
    • 为了减少模块之间的影响,扩展更容易

2.7.1. 狭义

  • 狭义:两个类之间不必彼此直接通信,那两个类就不应该发生直接的相互作用

  • 例子:在a对象中需要调用c的功能

    • 不遵守迪米特法则:b.getC.getTemp()
      • 若B不使用C,则A也需要修改
    • 遵守迪米特法则:使用Wrapper Method:, b.getTemp()
      • 若B不使用C,而是用其他类,变化对A不可见

image.png

  • 分析:降低类的耦合,但是造成模块之间通信效率降低(大量Wrapper

2.7.2. 广义

  • 指对对象之间的信息流量流向以及信息的影响的控制,主要是对信息隐藏的控制

  • 例子:使用控制器封装系统局部的复杂性

image.png
image.png

在 JDK 中,java.util.Stack是 java.util.Vector类的子类,该设计合理吗?若不合理,请分析解释该设计存在的问题。

违反里氏代换原则,使用Vector的地方不能替换成Stack。

2.8. 封装可变性原则

识别出变化,把变化的部分和不变的部分分离

  • 标题: 00-软件系统设计
  • 作者: Charlie
  • 创建于 : 2024-02-27 14:02:00
  • 更新于 : 2024-04-01 10:15:42
  • 链接: https://chillcharlie357.github.io/posts/243aaa51/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论