设计模式: 单一职责原则(SRP)- 让代码更易维护与测试

在软件开发和测试中,设计原则的合理运用直接影响系统的可维护性和稳定性。单一职责原则是设计原则的核心之一。

一、什么是单一职责原则?

单一职责原则(Single Responsibility Principle,SRP)是面向对象设计的核心原则之一,它的核心思想是:一个类应该只有一个引起它变化的原因。也就是说,一个类只负责完成一个职责或功能,从而避免职责的混杂和代码的过度复杂化。

代码优化示例:使用单一职责原则

优化前的代码:职责混杂

public class OrderService {

    /*
     *  传统的订单管理逻辑设计,包括创建、校验、数据存储等。
     */
    public void processOrder(String customerName, double amount) {
        // 创建订单
        Order order = createOrder(customerName, amount); 
        // 校验订单
        validateOrder(order); 
        // 保存订单
        saveOrder(order); 
    }

    private Order createOrder(String customerName, double amount) {
        return new Order(customerName, amount);
    }

    private void validateOrder(Order order) {
        if (order.getAmount() <= 0) {
            throw new IllegalArgumentException("订单金额必须大于零!");
        }
    }

     // 订单实体类
    public static class Order {
        private String customerName;
        private double amount;
        public Order(String customerName, double amount) {
            this.customerName = customerName;
            this.amount = amount;
        }
        public double getAmount() {
            return amount;
        }
        @Override
        public String toString() {
            return "Order[customerName=" + customerName + ", amount=" + amount + "]";
        }
    }
}

问题分析:

  • 一个类同时负责订单的创建、校验和保存,职责混杂。

  • 任何一个功能的修改都可能影响其他职责,增加代码维护难度。

优化后的代码:职责单一

将OrderService拆分为创建、校验、保存等多个类,每个类只专注于一个职责,降低耦合性。

1. 主协调类:OrderService

/**
 * OrderService 是订单业务的协调核心,按顺序完成订单创建、校验和保存。
 */
public class OrderService {

    private final OrderCreator orderCreator;       // 订单创建模块
    private final OrderValidator orderValidator;   // 订单校验模块
    private final OrderRepository orderRepository; // 订单保存模块

    /**
     * 构造函数注入依赖模块。
     */
    public OrderService(OrderCreator orderCreator, OrderValidator orderValidator, OrderRepository orderRepository) {
        this.orderCreator = orderCreator;
        this.orderValidator = orderValidator;
        this.orderRepository = orderRepository;
    }

    /**
     * 处理订单流程:创建、校验、保存。
     */
    public void processOrder(String customerName, double amount) {
        Order order = orderCreator.createOrder(customerName, amount); // 创建订单
        orderValidator.validate(order); // 校验订单
        orderRepository.saveOrder(order); // 保存订单
        System.out.println("订单处理完成:" + order);
    }
}

2. 订单创建模块:OrderCreator

public class OrderCreator {

    public Order createOrder(String customerName, double amount) {
        Order order = new Order();
        order.setCustomerName(customerName);
        order.setAmount(amount);
        System.out.println("订单创建成功:" + order);
        return order;
    }
}

3. 订单校验模块:OrderValidator

public class OrderValidator {

    public void validate(Order order) {
        if (order.getAmount() <= 0) {
            throw new IllegalArgumentException("订单金额必须大于零!");
        }
        System.out.println("订单校验通过:" + order);
    }
}

4. 订单保存模块:OrderRepository

public class OrderRepository {

    /**
     * 模拟保存订单的逻辑。
     * @param order 已通过校验的订单对象
     */
    public void saveOrder(Order order) {
        System.out.println("订单保存成功:" + order);
    }
}

5. 订单对象实体类:Order (略)

优化效果:

1.更高的解耦性

OrderService不再处理具体的订单创建逻辑,而是负责调用其他类,职责更加清晰。

2.类职责更加单一

如OrderCreator 专注于订单创建,未来如果订单创建的业务逻辑需要扩展,

比如对接外部系统或添加新的操作,不会影响OrderService的其他职责。

3.更容易测试

• 单元测试可以针对独立业务类进行,无需依赖OrderService。

• OrderService的测试可以通过 Mock 模拟其他类的行为,集中验证协调逻辑。

二、单一职责原则的价值

1. 简化单元测试

通过 SRP 分解功能,各个类职责单一,可以针对特定逻辑测试。以下是对OrderValidator的单元测试示例:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

/**
 * OrderValidator 单元测试,验证校验逻辑。
 */
public class OrderValidatorTest {

    @Test
    public void testValidate_ValidOrder() {
        Order order = new Order("张三", 100);
        OrderValidator validator = new OrderValidator();
        assertDoesNotThrow(() -> validator.validate(order)); // 无异常
    }

    @Test
    public void testValidate_InvalidOrder_AmountZero() {
        Order order = new Order("张三", 0);
        OrderValidator validator = new OrderValidator();
        Exception exception = assertThrows(IllegalArgumentException.class, () -> validator.validate(order));
        assertEquals("订单金额必须大于零!", exception.getMessage());
    }

    @Test
    public void testValidate_InvalidOrder_NegativeAmount() {
        Order order = new Order("张三", -100);
        OrderValidator validator = new OrderValidator();
        Exception exception = assertThrows(IllegalArgumentException.class, () -> validator.validate(order));
        assertEquals("订单金额必须大于零!", exception.getMessage());
    }
}

2. 快速应对需求变化

当业务需求变更或代码优化时,只需修改对应职责的类。

场景举例:新增订单校验逻辑(如增加订单金额小于 100,000),无需改动其他模块

public class OrderValidator {
    public void validate(Order order) {
        if (order.getAmount() <= 0) {
            throw new IllegalArgumentException("订单金额必须大于零!");
        }
        if (order.getAmount() > 100000) {
            throw new IllegalArgumentException("订单金额不得超过 100000!");
        }
        System.out.println("订单校验通过:" + order);
    }
}

测试改动简单,只需增加新校验逻辑部分,如

• 单元测试:对OrderValidator的测试类增加金额最大值校验用例。

• 接口测试:更新订单校验的正反用例等

• UI 测试:增加流程用例验证金额边界值和页面错误提示等。

三、如何判断是否用好了单一职责原则?

职责是否单一:类或方法是否专注于完成一项功能?

变更隔离性:需求变化时,是否只有一个类需要调整?

测试是否聚焦:单元测试是否可以很容易地针对单一逻辑进行?

四、总结

单一职责原则不仅是代码设计的核心理念,更是提升开发效率和测试质量的有力武器。它通过将复杂功能拆分为职责单一的模块,帮助团队实现以下目标:

1.降低耦合性,提升可维护性:代码结构更清晰,变更影响范围可控。

2.提升测试效率:测试逻辑聚焦单一模块,减少测试依赖和成本。

3.更精准的回归测试:明确测试范围,避免重复或遗漏测试内容。

4.优化自动化测试的维护性:职责清晰的类设计,使测试代码更易维护和扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小马不敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值