Skip to content

设计思想

软件设计的目标是构建「易维护、易扩展、易理解」的系统。这不是靠感觉,而是有一套经过验证的指导思想。本节介绍几个最核心的设计原则。

三个经典原则

DRY — Don't Repeat Yourself

不要重复你自己

同样的逻辑只写一次。如果你在两个地方看到几乎相同的代码,就应该考虑合并。

java
// ❌ 重复:两处验证逻辑一模一样
class UserValidator {
    public void validateUsername(String username) {
        if (username == null || username.isBlank()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        if (username.length() < 3) {
            throw new IllegalArgumentException("用户名至少3个字符");
        }
    }

    public void validateEmail(String email) {
        if (email == null || email.isBlank()) {
            throw new IllegalArgumentException("邮箱不能为空");
        }
        if (email.length() < 3) {  // 这段重复了!
            throw new IllegalArgumentException("邮箱至少3个字符");
        }
    }
}

// ✅ 提取公共验证方法
class StringValidator {
    public static void requireNonBlank(String value, String fieldName) {
        if (value == null || value.isBlank()) {
            throw new IllegalArgumentException(fieldName + "不能为空");
        }
    }

    public static void requireMinLength(String value, int minLength, String fieldName) {
        if (value != null && value.length() < minLength) {
            throw new IllegalArgumentException(fieldName + "至少" + minLength + "个字符");
        }
    }
}

DRY 不是「不能有重复代码」那么简单。真正的 DRY 是意图不重复,而不是「字符完全相同」。两处恰好相似的代码未必需要合并,但两处做同样事情的代码必须合并。

KISS — Keep It Simple, Stupid

保持简单,笨蛋

复杂的解决方案往往源于对问题的理解不够透彻。好的设计应该是简单的。

java
// ❌ 过度设计:为了「可扩展」引入不必要的抽象
interface Processor<T> {
    Result process(T input);
}

abstract class AbstractProcessor<T> implements Processor<T> {
    protected abstract Result doProcess(T input);
    public final Result process(T input) {
        return doProcess(input);
    }
}

class StringProcessor extends AbstractProcessor<String> {
    @Override
    protected Result doProcess(String input) {
        return new Result(input.toUpperCase());
    }
}

// ✅ 够用就好:直接解决问题
class StringProcessor {
    public String process(String input) {
        return input.toUpperCase();
    }
}

KISS 不是让你写烂代码。是在你设计一个可能有三个抽象层的系统之前,问问自己:「我真的需要这些吗?」

YAGNI — You Aren't Gonna Need It

你不会需要它的

不要为你认为以后可能需要的功能提前写代码。你对「未来需求」的预测往往是错的。

java
// ❌ YAGNI 反面:猜测未来需要多种支付方式
class PaymentService {
    public void payWithAlipay(Order order) { }
    public void payWithWechat(Order order) { }
    public void payWithPaypal(Order order) { }
    public void payWithCreditCard(Order order) { }
    public void payWithBankTransfer(Order order) { }
    // ... 一堆现在用不到的方法
}

// ✅ YAGNI 正面:只实现现在需要的
class PaymentService {
    public void pay(Order order, PaymentMethod method) {
        // 根据传入的支付方式处理
        // 未来新支付方式?到时候再加
    }
}

YAGNI 和 KISS 相辅相成。YAGNI 让你不要过度设计,KISS 让你把必须做的事做简单。

高内聚,低耦合

这是软件设计的终极目标。

内聚衡量一个模块内部各部分联系的紧密程度。高内聚意味着一个类只做一件事,把相关的东西放在一起。

耦合衡量不同模块之间的依赖程度。低耦合意味着类与类之间的联系尽可能少。

高内聚 + 低耦合 → 理想状态

类内部:职责单一,紧密相关
类之间:依赖最小,仅通过接口交流

一个实际的例子:

java
// ❌ 低内聚 + 高耦合:OrderService 做了太多事,还依赖具体实现
class BadOrderService {
    private MySQLOrderRepository repo;     // 耦合具体实现
    private SendGridEmailSender sender;    // 耦合具体实现
    private StripePaymentGateway gateway;   // 耦合具体实现

    public void createOrder(Order order) {
        // 验证、计算、保存、发邮件全在这里
        // 超过 200 行...
    }
}

// ✅ 高内聚 + 低耦合:每个类各司其职,通过接口交流
interface OrderRepository {
    void save(Order order);
}

interface NotificationService {
    void notify(Order order);
}

interface PaymentGateway {
    PaymentResult pay(Order order);
}

class OrderService {
    private final OrderRepository repository;
    private final NotificationService notifier;
    private final PaymentGateway paymentGateway;

    public OrderService(OrderRepository repository,
                       NotificationService notifier,
                       PaymentGateway paymentGateway) {
        this.repository = repository;
        this.notifier = notifier;
        this.paymentGateway = paymentGateway;
    }

    public void createOrder(Order order) {
        // 逻辑清晰,依赖注入,测试友好
    }
}

SOLID 原则

设计原则有很多,SOLID 是最核心的五个。如果只能记住一套原则,就记住它。

详细内容请查看 五大原则(SOLID)

总结

DRY       →  消除重复
KISS      →  保持简单
YAGNI     →  不要超前
高内聚    →  类内职责单一
低耦合    →  类间依赖最小
SOLID     →  面向对象设计的核心原则

这些原则不是教条,而是思考工具。面对设计决策时,用这些原则帮助判断,而不是盲目套用。

最好的代码是那些不需要注释就能读懂的代码。做到这一点,设计就不会太差。

基于 VitePress 构建