文章目录

  • SOLID
  • 单一职责原则
    • 其他判断标准
    • 过于单一的拆分
    • 例子
      • 序列化
  • 例子
    • 用户信息的例子
      • 从实际场景的角度出发
      • 从业务的角度出发
    • 总结

SOLID

  • 单一职责原则、开闭原则、里式替换原则、接口隔离原则和依赖反转原则,依次对应 SOLID 中的 S、O、L、I、D 这 5 个英文字母。我们今天要学习的是 SOLID 原则中的第一个原则:单一职责原则。
  • 换个角度来讲就是,一个类包含了两个或者两个以上业务不相干的功能,那我们就说它职责不够单一,应该将它拆分成多个功能更加单一、粒度更细的类。

单一职责原则

  • 单一职责原则的定义描述非常简单,也不难理解。一个类只负责完成一个职责或者功能。也就是说,不要设计大而全的类,要设计粒度小、功能单一的类
  • 换个角度来讲就是,一个类包含了两个或者两个以上业务不相干的功能,那我们就说它职责不够单一,应该将它拆分成多个功能更加单一、粒度更细的类。
比如,一个类里既包含订单的一些操作,又包含用户的一些操作。而订单和用户是两个独立的业务领域模型,我们将两个不相干的功能放到同一个类中,那就违反了单一职责原则
  • 单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP。这个原则的英文描述是这样的:A class or module should have a single reponsibility。
  • 这个原则描述的对象包含两个,一个是类(class),一个是模块(module)
    • 一种理解是:把模块看作比类更加抽象的概念,类也可以看作模块。
    • 另一种理解是:把模块看作比类更加粗粒度的代码块,模块中包含多个类,多个类组成一个模块

其他判断标准

  1. 类中的代码行数、函数或属性过多,会影响代码的可读性和可维护性,我们就需要考虑对类进行拆分;
那就是一个类的代码行数最好不能超过 200 行,函数个数及属性个数都最好不要超过 10 个
  • 从另一个角度来看,当一个类的代码,读起来让你头大了,实现某个功能时不知道该用哪个函数了,想用哪个函数翻半天都找不到了,只用到一个小功能要引入整个类(类中包含很多无关此功能实现的函数)的时候,这就说明类的行数、函数、属性过多了
  1. 类依赖的其他类过多,或者依赖类的其他类过多,不符合高内聚、低耦合的设计思想,我们就需要考虑对类进行拆分;
  2. 私有方法过多,我们就要考虑能否将私有方法独立到新的类中,设置为 public 方法,供更多的类使用,从而提高代码的复用性;
  3. 比较难给类起一个合适名字,很难用一个业务名词概括,或者只能用一些笼统的 Manager、Context 之类的词语来命名,这就说明类的职责定义得可能不够清晰;
  4. 类中大量的方法都是集中操作类中的某几个属性,比如,在 UserInfo 例子中,如果一半的方法都是在操作 address 信息,那就可以考虑将这几个属性和对应的方法拆分出来

过于单一的拆分

  • 单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性,以此来实现代码的高内聚、低耦合。
  • 但是,如果拆分得过细,实际上会适得其反,反倒会降低内聚性,也会影响代码的可维护性。

例子

序列化

  • 我们对 Serialization 类进一步拆分,拆分成一个只负责序列化工作的 Serializer 类和另一个只负责反序列化工作的 Deserializer 类

public class Serializer {private static final String IDENTIFIER_STRING = "UEUEUE;";private Gson gson;public Serializer() {this.gson = new Gson();}public String serialize(Map<String, String> object) {StringBuilder textBuilder = new StringBuilder();textBuilder.append(IDENTIFIER_STRING);textBuilder.append(gson.toJson(object));return textBuilder.toString();}
}public class Deserializer {private static final String IDENTIFIER_STRING = "UEUEUE;";private Gson gson;public Deserializer() {this.gson = new Gson();}public Map<String, String> deserialize(String text) {if (!text.startsWith(IDENTIFIER_STRING)) {return Collections.emptyMap();}String gsonStr = text.substring(IDENTIFIER_STRING.length());return gson.fromJson(gsonStr, Map.class);}
}
  • 虽然经过拆分之后,Serializer 类和 Deserializer 类的职责更加单一了,但也随之带来了新的问题。如果我们修改了协议的格式,数据标识从“UEUEUE”改为“DFDFDF”,或者序列化方式从 JSON 改为了 XML,那 Serializer 类和 Deserializer 类都需要做相应的修改,代码的内聚性显然没有原来 Serialization 高了。
  • 如果我们仅仅对 Serializer 类做了协议修改,而忘记了修改 Deserializer 类的代码,那就会导致序列化、反序列化不匹配,程序运行出错,也就是说,拆分之后,代码的可维护性变差了

例子

用户信息的例子

public class UserInfo {private long userId;private String username;private String email;private String telephone;private long createTime;private long lastLoginTime;private String avatarUrl;private String provinceOfAddress; // 省private String cityOfAddress; // 市private String regionOfAddress; // 区 private String detailedAddress; // 详细地址// ...省略其他属性和方法...
}
  • 一种观点是,UserInfo 类包含的都是跟用户相关的信息,所有的属性和方法都隶属于用户这样一个业务模型,满足单一职责原则
  • 另一种观点是,地址信息在 UserInfo 类中,所占的比重比较高,可以继续拆分成独立的 UserAddress 类,UserInfo 只保留除 Address 之外的其他信息,拆分之后的两个类的职责更加单一

从实际场景的角度出发

  • 我们不能脱离具体的应用场景。如果在这个社交产品中,用户的地址信息跟其他信息一样,只是单纯地用来展示,那 UserInfo 现在的设计就是合理的。
  • 如果这个社交产品发展得比较好,之后又在产品中添加了电商的模块,用户的地址信息还会用在电商物流中,那我们最好将地址信息从 UserInfo 中拆分出来,独立成用户物流信息(或者叫地址信息、收货信息等)
  • 如果做这个社交产品的公司发展得越来越好,公司内部又开发出了跟多其他产品(可以理解为其他 App)。公司希望支持统一账号系统,也就是用户一个账号可以在公司内部的所有产品中登录。这个时候,我们就需要继续对 UserInfo 进行拆分,将跟身份认证相关的信息(比如,email、telephone 等)抽取成独立的类

从业务的角度出发

  • 如果我们从更加细分的“用户展示信息”“地址信息”“登录认证信息”等等这些更细粒度的业务层面来看,那 UserInfo 就应该继续拆分。

总结

  • 我们可以总结出,不同的应用场景、不同阶段的需求背景下,对同一个类的职责是否单一的判定,可能都是不一样的
  • 在某种应用场景或者当下的需求背景下,一个类的设计可能已经满足单一职责原则了,
  • 但如果换个应用场景或着在未来的某个需求背景下,可能就不满足了,需要继续拆分成粒度更细的类。
  • 在真正的软件开发中,我们也没必要过于未雨绸缪,过度设计。所以,我们可以先写一个粗粒度的类,满足业务需求。随着业务的发展,如果粗粒度的类越来越庞大,代码越来越多,这个时候,我们就可以将这个粗粒度的类,拆分成几个更细粒度的类。这就是所谓的持续重构(

设计原则—SOLID(SRP)相关推荐

  1. 六大设计原则SOLID

    六大设计原则SOLID 一.SOLID 设计模式的六大原则 二.单一职责原则 (Single Responsibility Principle) 1. 单一职责原则定义 2. 问题由来 3. 解决方案 ...

  2. 流行20年的架构设计原则SOLID可能已经不适合微服务了

    点击上方"服务端思维",选择"设为星标" 回复"669"获取独家整理的精选资料集 回复"加群"加入全国服务端高端社群「后 ...

  3. 【六大设计原则-SOLID】

    SOLID简介: 历史:由Robert C·Martin汇总并推广 目标: 使软件更容易被改动 是软件更容易被理解 构建可以在多个软件系统中复用的组件 组成: 名称 简写 含义 单一职责原则 SRP ...

  4. 软件设计原则SOLID+组合聚合+迪米特原则(附代码讲解)

    SOLID是五大设计原则的首字母简写,最早出现于出自Robert Martin(罗伯特. 马丁)的<架构整洁之道>第三章设计原则.他们分别是 single Responsibility P ...

  5. 设计原则——SOLID

    SOLID是5个设计原则的统称,它们分别是:单一职责原则.开闭原则.里式替换原则.接口隔离原则和依赖反转原则,依次对应SOLID中的S.O.L.I.D. 1.单一职责原则 单一职责原则,Single ...

  6. 六大设计原则(SOLID)

    一.SOLID 设计模式的六大原则有: Single Responsibility Principle:单一职责原则 Open Closed Principle:开闭原则 Liskov Substit ...

  7. 六大设计原则 (SOLID)

    设计原则概述 设计模式中主要有六大设计原则,简称为SOLID ,是由于各个原则的首字母简称合并的来(两个L算一个,solid 稳定的),六大设计原则分别如下: 1.单一职责原则(Single Resp ...

  8. 设计原则—SOLID(LSP)

    文章目录 里氏替换原则 落地 测试 反例 子类违背父类声明要实现的功能 子类违背父类对输入.输出.异常的约定 异常 输入 子类违背父类注释中所罗列的任何特殊说明 意义 对比多态 改进已有实现 指导程序 ...

  9. 设计原则—SOLID(DIP)

    文章目录 依赖反转原则(DIP) 正确理解 优势 控制反转 例子 依赖注入(DI) 例子 依赖注入框架 对比基于接口编程 相同点 区别 总结 依赖反转原则(DIP) 高层模块(high-level m ...

最新文章

  1. Spring Security 进阶干货:自定义配置类入口WebSecurityConfigurerAdapter
  2. TensorFlow文本摘要生成 - 基于注意力的序列到序列模型
  3. 帧中继中配EIGRP(hub-spoke)
  4. 行业B2B网站策划6个基本要求
  5. [心得分享] 我在 GitHub 上学习开源
  6. jQuery 插入元素
  7. Android 关于长按back键退出应用程序的实现
  8. 移动网页如何实现发送短信和拨打电话的功能
  9. HTML5 canvas绘制雪花飘落动画(需求分析、知识点、程序编写分布详解)
  10. 从实现原理来讲,Nacos 为什么这么强
  11. idea lib下有jar包但是仍然报错 找不到类
  12. 会做饭的机器人曰记_会做饭的机器人作文二百字
  13. windows系统镜像文件汇总
  14. java 图片转pdf_在Java语言中将图像转换为PDF?Spire.PDF for Java轻松搞定!
  15. 经济机器是怎样运行的(文字版)-瑞.达利欧
  16. 算法竞赛资料整理分享
  17. webAppRootKey
  18. 召唤神龙无敌版------小鱼吃大龙
  19. 【老九学堂】【C++】CodeBlocks安装配置
  20. 留学生VS应届生,留学生在当下还有求职优势吗

热门文章

  1. 反射模式python
  2. 一个定时器实现IO模拟pwm,呼吸灯效果
  3. opencv Day1
  4. 光头老法师手持尼康却能玩出佳能的效果
  5. 各个专业375个国家级精品课程的网址
  6. 知识工作效率八段锦 【51PPT】
  7. 俏江南“倒闭”真相:对员工好坏,直接决定了企业的生死!
  8. centos7下详细搭建Mongodb集群
  9. OpenJWeb(1.6) Java Web应用快速开发平台技术白皮书
  10. css的hue-rotate是调整了色相吗?