来源:mikechen的互联网架构
在设计模式 7 大原则中,单一职责原则最简单,但又较难运用。
单一职责原则的核心思想是:让专业的人,做专业的事。
就如同医生和护士,各有自己特定的职责,且专注于自己的职责。
单一职责原单一职责原则既是架构设计的基石,也是 Java 面试高频必考点,非常重要。
大家好,我是mikechen。
本篇,我会通过【图例+源码】结合,详解单一职责原则。
单一职责原则是什么
为什么要遵循单一职责原则
单一职责原则的 UML 类图
单一职责原则的 3 大优点
单一职责原则的实现原理及示例
PS.
Mike 已将本文内容归纳到《Java面试突击合集》PDF,方便大家面试通关。
《Java面试突击合集》PDF 已收录了 600+ 道大厂面试真题,约 14 万字,350页。
助力面试突击,提高面试通关率,文末自取。

单一职责原则,英文全称 Single Responsibility Principle,又称为单一功能原则。
单一职责原则是指一个类要职责单一,只负责一个特定的功能或任务,而不应该承担过多的职责,使得代码更容易理解、维护和扩展。
遵循单一职责原则,每个类都专注于一个明确的职责,可以降低代码的复杂性,提高代码的可维护性。
如果一个类承担了太多的职责,就会难以维护和修改。
一个职责的变化,可能会削弱这个类实现其他职责的能力;
当客户端需要该对象的某一个职责时,需要将其它不需要的职责全部包含进来,这样会导致代码冗余。
单一职责原则的 UML 类图:

在 UML 类图中,虚线箭头表示依赖关系,常用在方法、参数等,由依赖方指向被依赖方。
在实践了单一职责原则的 UML 类图中,不属于 Employee 的两个职责,则被分成了两类:
FinancialApartment 类
HRApartment 类
我们再来看一个具体的示例。
假设:
一个医院系统中,有一个名为 Doctor(医生)的类,这个类负责管理医生的信息和诊断患者。
class Doctor {private String name;private String specialization;public Doctor(String name, String specialization) {this.name = name;this.specialization = specialization;}public void diagnosePatient(Patient patient) {// 实现诊断患者的逻辑}public void prescribeMedicine(Patient patient, String medicine) {// 实现给患者开药的逻辑}public void scheduleSurgery(Patient patient, Date date) {// 实现安排手术的逻辑}// 其他与医生信息相关的方法和属性}
在这个示例中,Doctor 类不仅管理医生的信息,还包含了与患者的诊断、处方药和手术安排相关的方法。
在 Doctor 类中,包含了 4 种不同的逻辑:
诊断患者;
给患者开药;
安排手术;
其他与医生信息相关的方法和属性。
这个逻辑看似没问题,但不符合单一职责原则,因为这四种逻辑各不相同。
这样的设计会带来什么影响呢?
我们想象下,如果业务发生了变化,就需要去修改当前这个类。牵一发而动全身,这样设计显然不合理。
因此,我们需要对类中的不同责任进行拆分:
class Doctor {private String name;private String specialization;public Doctor(String name, String specialization) {this.name = name;this.specialization = specialization;}// 医生信息管理的方法和属性// ...}class Patient {// 患者信息管理的方法和属性// ...}class MedicalStaff {public void diagnosePatient(Doctor doctor, Patient patient) {// 实现诊断患者的逻辑}public void prescribeMedicine(Doctor doctor, Patient patient, String medicine) {// 实现给患者开药的逻辑}public void scheduleSurgery(Doctor doctor, Patient patient, Date date) {// 实现安排手术的逻辑}}
现在,将医生的信息管理、以及患者的诊断、处方药、手术安排等功能,分别分配给不同的类:
Doctor 类:负责医生的信息管理;
Patient 类:负责患者的信息管理;
MedicalStaff 类:负责医疗工作。
使用单一职责原则,将这些职责分离开来,让每个类都有自己明确的职责,且只有一个职责。
由于职责区分,各个类的变化不会相互影响,代码容易理解和维护。
这里可能有同学会问,怎么判断是否需要分离职责?或者说分离职责的依据是什么?
是否需要分离职责,主要则取决于变化:
当变化发生,只影响其中一个职责,需要拆分;
如果变化都影响到这两个职责,则不需要拆分。
根据以上,我们总结出了单一职责原则的优点:
可以降低类的复杂性;
可以提高代码的可读性、可维护性;
可以降低变更引起的风险。
示例:
在一个电商订单处理系统中,有两个职责:订单管理、发货处理。
我们可以使用单一职责原则,将这两个职责分离开来:
// 订单管理类负责处理订单的创建、修改和查询class OrderManager {public void createOrder(Order order) {// 实现订单创建逻辑}public void updateOrder(Order order) {// 实现订单修改逻辑}public Order getOrder(int orderId) {// 实现订单查询逻辑return null;}}// 发货处理类负责处理订单的发货操作class ShippingProcessor {public void shipOrder(Order order) {// 实现订单发货逻辑}}// 订单类,包含订单的相关信息class Order {private int orderId;private String customerName;private String shippingAddress;// 其他订单信息的成员变量和方法public Order(int orderId, String customerName, String shippingAddress) {this.orderId = orderId;this.customerName = customerName;this.shippingAddress = shippingAddress;// 初始化其他订单信息}// 其他订单操作的方法和属性访问器}public class Main {public static void main(String[] args) {OrderManager orderManager = new OrderManager();ShippingProcessor shippingProcessor = new ShippingProcessor();// 创建订单Order newOrder = new Order(1, "John Doe", "123 Main St");orderManager.createOrder(newOrder);// 查询订单Order retrievedOrder = orderManager.getOrder(1);// 发货订单shippingProcessor.shipOrder(retrievedOrder);}}
在这个示例中:
OrderManager 类:负责订单的创建、修改和查询;
ShippingProcessor 类:负责订单的发货操作。
每个类都有明确的职责,且只负责一个职责,避免了不必要的复杂性和依赖关系。
本文重点介绍了单一职责原则的核心知识点。
单一职责原则的核心思想是让每个类专注于一个明确的职责,以提高代码的可维护性和可读性。适用于类、接口、方法中。
单一职责原则的难点在于如何将类的职责划分得清晰明了,如何识别和消除不必要的职责......。在实际开发中,我们很容易将不同的责任归类在一起,或者过度拆分。
是否需要拆分职责,参考思路:当变化发生,只影响其中一个职责,那就需要拆分。如果变化都影响到这两个职责,那就不需要拆分。
合理拆分职责的前提:设计者需要对业务足够了解、同时具备较强的分析设计能力及相关实践经验,这个部分在 Mike 的架构专题中有详解。