CloudNativeEra
  • Introduction
  • 名词解释
  • Computer Science
    • Computer Organization
      • CPU
      • 二进制、电路、加法器、乘法器
      • 编译、链接、装载
      • 存储器
      • IO
    • Operating System
      • 操作系统基础知识
      • 系统初始化
      • 进程管理
      • Everything about Memory
      • 文件系统
      • 并行编程
      • Linux
        • CPU
        • IO 多路复用
        • DMA IO and Linux Zero Copy
    • Computer Network
      • 网络相关命令
      • 评估系统的网络性能
      • 网络抓包
      • Linux 最多支撑的 TCP 连接
      • 网络虚拟化
      • DHCP 工作原理
    • Data Structure and Algorithm
      • 题目列表
      • Summarize
        • 方法总结
        • 二分思想
        • 树的演化
        • 算法思想总结
      • Data Structure
        • Data Struct - Array
        • Tree
        • Heap
        • Hash
        • 字符串
      • Algorithm
        • Sorting Algorithm
        • 查找
        • 贪心算法
        • 动态规划
        • 位运算
      • Practice Topics
        • Data Struct in SDK
        • Topic - Tree
        • Topic - Graph
        • Topic - 滑动窗口
        • 剑指 Offer 题解
    • 并发编程
      • 并发模式
      • 并发模型
  • 系统设计
    • 软件设计
      • 软件架构
      • 编程范式
      • 系统设计题
      • 设计原则
      • 计算机程序的构造和解释 SICP
    • 领域驱动设计
      • 应用:在线请假考勤管理
      • 应用: library
    • 微服务与云原生
      • Designing and deploying microservices
      • 容器技术
      • Docker
      • Etcd
      • Kubernetes
        • Kubernetes - Mapping External Services
      • Istio
      • 监控
    • 分布式系统
      • 分布式理论
      • 分布式事务
    • 后端存储设计
      • 缓存设计
      • 数据库架构设计
    • CI/CD
    • 设计最佳实践
    • 测试
    • 安全
    • 综合
      • 开发实践
      • 分布式锁
      • 分布式计数服务
      • 弹幕系统设计
      • 消息队列设计
      • 分布式ID生成算法
      • 限流设计
      • 网关设计
      • 通用的幂等设计
      • 分布式任务调度
        • Timer
        • ScheduledExecutorService
        • Spring Task
        • Quartz
      • 交易系统
      • 权限设计
  • 编程语言
    • 编程语言
    • C & C++
    • Java
      • JVM
        • JVM Bytecode
      • Java 核心技术
      • Java 8 新特性
      • Java 集合框架
      • Java NIO
      • 并发编程
        • 线程生命周期与线程中断
        • 三个线程交替打印
        • 两个线程交替打印奇偶
        • 优雅终止线程
        • 等待通知机制
        • 万能钥匙:管程
        • 限流器
        • 无锁方案 CAS
    • Java 源码阅读
      • Unsafe
      • 异步计算 Future
      • Java Queue
      • CoalescingRingBuffer 分析
      • Java Collections
        • PriorityQueue 分析
        • HashMap 分析
        • TreeMap
    • Golang
    • Python
  • 框架/组件/类库
    • Guava
      • Guava Cache
      • Guava EventBus
    • RxJava
    • Apache MINA
    • Netty
      • 网络 IO 模型
      • Netty 生产问题
    • Apache Tomcat
    • MyBatis
    • 限流框架
    • Spring Framework
      • Spring Core
      • Spring 事务管理
    • Spring Boot
    • Spring Cloud
      • Feign & OpenFeign
      • Ribbon
      • Eurake
      • Spring Cloud Config
    • FixJ
    • Metrics
    • Vert.x
  • 中间件
    • Redis
      • Redis 基础
        • Redis 数据结构设计与实现
        • Redis 高性能网络模型
      • Redis checklist
      • 应用案例 - Redis 数据结构
      • 应用案例 - Redis 缓存应用
      • 应用案例 - Redis 集群
      • Redis 客户端
      • Redis 生产案例
        • [译] 在 Redis 中存储数亿个简单键值对
    • MySQL
      • MySQL 基础
      • MySQL Index
      • MySQL Transaction
      • MySQL 优化
      • MySQL 内核
      • MySQL Command
      • MySQL Checklist
      • MySQL Analysis Tool
      • 实现 MySQL
    • State Machine
    • 数据库连接池
    • MQ
      • 高性能内存队列 Disruptor
      • Kafka
      • Pulsar
      • RocketMQ
        • Broker 的设计与实现
      • NSQ
  • 实际案例
    • 线上 Case
      • Request Aborted
      • MySQL - Specified key was too long
      • Java 应用 CPU 100% 排查优化
      • 频繁 GC 导致的 Java 服务不响应
      • 导出优化
  • 大数据
    • 流计算
    • Flink
  • 其他
    • 工具
    • 读书
      • 设计数据密集型应用
      • 实现领域驱动设计
      • 精通比特币
      • 提问的智慧
    • 论文
    • 工程博客
    • 阅读源码
    • 面试
      • 如何在最短的时间里对对方有个全面的了解
    • 分享
    • 软技能
    • Todo
  • Blog
    • #算法
      • 查找
      • 位运算
      • 树
    • #架构
      • 1- 通信
    • Design & Dev & Opt
      • High Performance Data structure Design
  • Tiny Project
    • A Simple WeChat-like Instant Messaging Platform
由 GitBook 提供支持
在本页
  • SRP 单一职责原则
  • OCP 开闭原则
  • LSP 里式替换原则
  • ISP 接口隔离原则

这有帮助吗?

  1. 系统设计
  2. 软件设计

设计原则

时刻保持动态的眼光来看待这些设计原则

SRP 单一职责原则

SRP,Single Responsibility Principle. 这个原则的核心是:一个类或者模块只负责完成一个职责(或功能)。

解读:

  • SRP 并不好把控,没有一个放之四海而皆准的标准;有时候也理解为只有一个原因引起类或模块的变化,都非常抽象和模糊,并不具体,所以 SRP 真的去落地到实际项目就会有难度;所以,职责划分是 SRP 最难的,如何找到职责边界,如何落地,在不同的情境下对职责的理解和考量又不尽相同

  • 不同需求阶段,不同应用场景,不同业务角度去理解和应用 SRP 都是不一样的,这个需要通过大量的实战来总结经验,找到 SRP 的“感觉”;但是可以采取持续重构的方式来应对 SRP,尽量让模块和类的设计满足它,可以作为设计时的指导原则和意识。

  • 在实际应用中,不要设计大而全的类,要设计粒度小、功能单一的类,如果某个类或模块承担了过多的职责,那就可以考虑将它拆分成多个类或模块;可以说 SRP 是高内聚的一种体现或指导原则,把相同的功能或职责内聚到一个类或模块中,不同类和模块之间以一种代价最小的方式组装在一起,类和类、模块和模块之间必定存在联系,如果没有联系的两件东西放在一起毫无价值,而这种联系的强弱和稳定度是需要重点考虑的,SRP 是从职责和功能的角度来界定内聚的标准和耦合的尺度,告诉我们做设计时要从自己理解的角度去做需求拆分、功能拆分、子系统拆分、模块拆分、类的拆分、方法的拆分,而不是用一个大而全的东西包含所有的,拆分能带来职责明晰,多方协作,这不正是真实世界的运作机制吗

其实,我很想能思考明白 SRP 的本质是什么,但是它确实太抽象太模糊,我认为的如何应用 SRP 的一般方法:

  1. 首先要有 SRP 的意识,总结为意识先行;

  2. 其次善于利用持续重构的方式,不要做过度设计,做符合当前需求和情景的设计,尽量保持类或模块的小粒度和功能单一,总结为重构开路;

  3. 最后总结经验,培养感觉,在实战中提升,总结为积累经验;

SRP 意识先行,持续重构开路,实战中积累经验。

简单理解 SRP 就是要从职责的层面做到分工明确。

OCP 开闭原则

OCP 说的是对软件实体(模块、类、方法等)应该对扩展开放,对修改关闭。

OCP 并不是说不需要修改代码,而是从软件设计和功能语义层面去理解,要认识到,添加一个新功能,不可能任何模块、类、方法的代码都不“修改”,这个是做不到的。类需要创建、组装、并且做一些初始化操作,才能构建成可运行的的程序,这部分代码的修改是在所难免的。我们要做的是尽量让修改操作更集中、更少、更上层,尽量让最核心、最复杂的那部分逻辑代码满足开闭原则。比如说骨架需要是稳定的,这里就不要做过多修改,而枝叶是多种多样的,这里就要做好灵活的扩展机制了。再通俗点的理解:我们有一个稳定的结构,在这个基础之上可以支持尽可能多的扩展能力,扩展能力就是对扩展开放,稳定结构就是对修改关闭。举个例子,CPU 大家都了解,CPU 的设计就符合 OCP,CPU 分为计算单元、控制单元、数据单元和一系列指令,这个结构是稳定的,CPU 进化了那么多年依然是这么工作的,但是 CPU 的能力可以无限扩展的,CPU 可以处理文本数据、图像、音视频等等,但是都不需要修改 CPU 本身。

OCP 是一个指导原则,指导我们设计出有稳定结构且可以无限扩展的架构,更好的将可变部分和不变部分隔离开。做到 OCP 不是一件容易的事情:

  1. 首先要有抽象、封装、扩展的意识,有这些意识是做好事情的前提;就是在做的时候,花点时间去多思考,不同角度反复推敲,比如未来哪些需求可能会变,是不是要留扩展点,代码结构怎么设计,单测怎么设计,会不会严重违反某些好的指导原则等

  2. 多态、依赖注入、基于接口而非实现编程、抽象等都是实现 OCP 的具体方式

  3. 一些常见的设计模式也可以做到 OCP

为什么我们要“对扩展开放、对修改关闭”?

做任何事情都需要进行积累,从0到1,从1到2,从2到3...这样一步步的完成我们的目标,这个过程中就需要有一个稳定的地基来承载每一步带来的变化,当然地基本身的稳定性也是一点点重构出来的,随着理解的加深,地基就越来越稳定,新的需求在已有的功能上进行迭代,这是我们追求的最好的样子,不浪费以前的工作,继续开展新的工作,日积月累完成最终的目标。所以 OCP 就是这样一种指导原则,提醒我们在做事情时要识别稳定点和变化点,将稳定点满满的沉淀为稳定的地基,将变化点演变为灵活的扩展点,只有这样才是最高效的。这样我们就可以利用抽象意识,多态、依赖注入、面向接口编程等很多方式去落地代码,达到不浪费以前工作,继续基础新功能的目的。

LSP 里式替换原则

LSP 是这样描述的:子类对象(object of subtype/derived class)能够替换程序(program)中父类对象(object of base/parent class)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏。

LSP 有两个关键点:

  1. 子类可以替换父类

  2. 要保证原来程序的逻辑行为(behavior)不变及正确性不被破坏

时刻抓住这两点,就能很好判断一段程序或者一个设计是否符合 LSP。如果子类替换父类后产生了协议之外的副作用,就说明违背了 LSP,可能会造成很多未知的错误,或者引发其他系统的错误。

LSP 告诉我们一定要严格按照协议设计来实现,LSP 可以用于接口设计、类设计、方法设计等。

此外,多态和里式替换有点类似,但它们关注的角度是不一样的。多态是面向对象编程的一大特性,也是面向对象编程语言的一种语法。它是一种代码实现的思路。而里式替换是一种设计原则,是用来指导继承关系中子类该如何设计的,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。

ISP 接口隔离原则

ISP 是这样描述的:客户端不应该强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。

ISP 的核心是来指导接口的设计,告诉我们要结合具体使用场景,侧重于如何设计接口才是更加合理的,ISP 给了一个判断标准,如果使用者只依赖接口的部分功能,就需要把接口的功能拆分成多个接口,进行细化;如果使用者只依赖部分接口,那就需要把其他接口功能做隔离,放到其他接口的上下文中

上一页系统设计题下一页计算机程序的构造和解释 SICP

最后更新于5年前

这有帮助吗?