Skip to content

设计原则

字数: 0 字 时长: 0 分钟

在有了一定的编程经历之后,特别是工作中对大量功能模块代码重构的经历,越来越认识到良好的设计有利于软件的可读性、健壮性和可维护性。项目模块代码规模较小可以选择推翻重来,如果涉及代码规模较大,甚至涉及到多个团队共同维护的模块,在后期维护扩展时往往会花费大量的成本去弥补初期的不良设计。

因此,有必要系统学习设计模式相关知识,提升编码架构设计能力和阅读源码的能力。

1. 单一职责原则

一个类,只干一件事,只处理一个独立的功能领域

java
// 违反单一职责的案例:报表生成器承担双重职责
class ReportGenerator {
    public void fetchDataFromDB() { ... }  // 职责1: 数据获取
    public void formatToPDF() { ... }      // 职责2: 格式转换
  
    // 重构为:
    // DataFetcher 类负责数据获取
    // PdfFormatter 类负责格式转换
}

2. 开闭原则

对扩展开放,对修改关闭。当我们新增功能时,新增代码即可,而不必去修改已有的类或方法。这一点,我深有体验,在工作中很多时候新增功能时都需要改动已有的类或方法,有时候往往需要测试对已有功能是否有影响,加大风险,不利于维护。

3. 里氏替换原则

子类必须能够完全替代其基类而不会破坏原有系统功能。也就是继承关系不能乱用,继承不是为了代码复用,而是为了保持通用的行为,如需代码复用可以选择组合的方式。

4. 接口隔离原则

客户端不应被迫依赖其不需要的方法。也就是接口只定义足够且必要的方法,如果定义的太多,实现类也不得不实现这些根本不需要的方法。

5. 依赖倒置原则

高层模块不应该依赖底层模块,二者都应该依赖抽象。也就是面向接口编程,而不是具体的实现。

java
// 违规:直接依赖具体类
class OrderService {
    private MySQLOrderDao dao = new MySQLOrderDao(); 
}

// 合规:依赖抽象
class OrderService {
    private final OrderDao dao; // 接口依赖
    public OrderService(OrderDao dao) {
        this.dao = dao;
    }
}

6. 迪米特法则

只与直接相关的类交流,尽量减少对外部对象内部细节的依赖。《Effective Java》 中作者提到了,区分一个组件设计得好不好,唯一重要的因素在于,它对外部的其他组件而言,是否隐藏了其内部数据和实现细节。这就是封装,有利于解耦。

java
// 违规方案:跨越多个对象层级,暴露不必要的细节
user.getAccount().getBalance().format();

// 合规方案:通过封装减少依赖链
user.getFormattedBalance(); // User内部处理格式化逻辑

7. KISS 保持简单

KISS (Keep it Stupid Simple),保持简单,避免过度设计。这条原则应该是最难的,需要根据实际情况把握设计考量:

  • 在开发非核心场景,比如某个临时场景(比如仅仅为了应付某次特殊上线需求)时可以采取这条原则
  • 开发核心场景时(比如支付模块)优先采取前 6 条设计原则,保持一个良好的架构设计