吃透单一职责原则,100倍效果提升代码质量

来源:mikechen的互联网架构

设计模式 7 大原则中,单一职责原则最简单,但又较难运用。

单一职责原则的核心思想是:让专业的人,做专业的事。

就如同医生和护士,各有自己特定的职责,且专注于自己的职责。

单一职责原单一职责原则既是架构设计的基石,也是 Java 面试高频必考点,非常重要。

大家好,我是mikechen。

本篇,我会通过【图例+源码】结合,详解单一职责原则

  • 单一职责原则是什么

  • 为什么要遵循单一职责原则

  • 单一职责原则的 UML 类图

  • 单一职责原则的 3 大优点

  • 单一职责原则的实现原理及示例


PS.

Mike 已将本文内容归纳到《Java面试突击合集》PDF,方便大家面试通关。

《Java面试突击合集》PDF 已收录了 600+ 道大厂面试真题,约 14 万字,350页。

助力面试突击,提高面试通关率末自取


01
   什么是单一职责原则


单一职责原则,英文全称 Single Responsibility Principle,又称为单一功能原则


单一职责原则是指一个类要职责单一,只负责一个特定的功能或任务,而不应该承担过多的职责,使得代码更容易理解、维护和扩展。

 

02
  为什么要遵循单一职责原则


遵循单一职责原则,每个类都专注于一个明确的职责,可以降低代码的复杂性,提高代码的可维护性。


如果一个类承担了太多的职责,就会难以维护和修改。


  • 一个职责的变化,可能会削弱这个类实现其他职责的能力;


  • 当客户端需要该对象的某一个职责时,需要将其它不需要的职责全部包含进来,这样会导致代码冗余。


单一职责原则的 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 类:负责医疗工作。


使用单一职责原则,将这些职责分离开来,让每个类都有自己明确的职责,且只有一个职责。

由于职责区分,各个类的变化不会相互影响,代码容易理解和维护。

这里可能有同学会问,怎么判断是否需要分离职责?或者说分离职责的依据是什么?

是否需要分离职责,主要则取决于变化:

  • 当变化发生,只影响其中一个职责,需要拆分;


  • 如果变化都影响到这两个职责,则不需要拆分。


03
  单一职责原则的三大优点


根据以上,我们总结出了单一职责原则的优点:

  • 可以降低类的复杂性;


  • 可以提高代码的可读性、可维护性;


  • 可以降低变更引起的风险。

 

04
  单一职责原则的实现示例


示例:

在一个电商订单处理系统中,有两个职责:订单管理、发货处理。

我们可以使用单一职责原则,将这两个职责分离开来:

























































// 订单管理类负责处理订单的创建、修改和查询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 的架构专题中有详解。

请使用浏览器的分享功能分享到微信等