Skip to content

代码规范实践:让代码说话

前面我们聊了异常、命名、格式化、集合...

这些规范如果不落地到日常开发中,就只是纸面上的东西。

这一节聊聊怎么在实际项目中真正用起来。

方法设计

好方法的特征:单一职责、参数适量、名字清晰。

方法不要太长

一个方法最好不超过一屏(约 50 行),超长就拆:

java
// ❌ 一个方法做了太多事
public void processOrder(Order order) {
    // 校验订单
    if (order == null) throw new IllegalArgumentException();
    if (order.getItems() == null || order.getItems().isEmpty()) {
        throw new IllegalArgumentException("订单项不能为空");
    }
    // 计算价格
    double total = 0;
    for (OrderItem item : order.getItems()) {
        total += item.getPrice() * item.getQuantity();
    }
    // 应用折扣
    if (total > 1000) total *= 0.9;
    // 验证库存
    for (OrderItem item : order.getItems()) {
        if (!inventoryService.checkStock(item)) {
            throw new OutOfStockException(item.getProductId());
        }
    }
    // 保存订单
    order.setTotal(total);
    orderRepository.save(order);
    // 发通知
    notificationService.sendOrderConfirmation(order);
}

// ✅ 重构后,每个方法只做一件事
public void processOrder(Order order) {
    validateOrder(order);
    double total = calculateTotal(order);
    applyDiscount(total);
    checkInventory(order);
    saveAndNotify(order);
}

参数不宜过多

参数超过 3 个就该考虑用参数对象了:

java
// ❌ 参数过多,调用方痛苦
public void createUser(String firstName, String lastName, String email,
    String phone, String address, int age, boolean isActive) {
}

// ✅ 用 DTO
public void createUser(UserCreateDTO dto) {
}

注释规范

好注释解释为什么,不解释是什么。代码本身应该自解释。

解释不直观的设计决策

java
// ❌ 注释什么:代码已经说了
// 设置用户名为 zhang
user.setName("zhang");

// ✅ 解释为什么:不能从代码本身看出来的原因
// 密码最小长度 8 位,但考虑到用户习惯,设为 6 位过渡期
private static final int PASSWORD_MIN_LENGTH = 6;

// ✅ 解释魔法值
// 为什么用 86400:每天的秒数
private static final long EXPIRY_DAYS = 7;
private static final long EXPIRY_SECONDS = EXPIRY_DAYS * 24 * 60 * 60; // 604800

不要写废话注释

java
// ❌ 废话注释
/**
 * Sets the user name.
 * @param name the user name
 */
public void setName(String name) {
    this.name = name;
}

// ✅ 如果方法名足够清晰,就不需要 Javadoc
public void setName(String name) {
    this.name = name;
}

// ✅ 需要给调用方看的复杂逻辑说明,才需要 Javadoc
/**
 * 根据传入的优惠码计算折扣。
 * 规则:VIP 用户额外 5% 折扣,新用户首单 10 元优惠,
 * 两种优惠不叠加,取较大值。
 */
public Discount calculateDiscount(User user, String couponCode) { ... }

类设计

单一职责

一个类只做一件事,这样更容易理解、测试和维护:

java
// ❌ 上帝类:所有功能都往里塞
class UserManager {
    void createUser() {}
    void deleteUser() {}
    void sendEmail() {}  // 为什么邮件在用户管理里?
    void generateReport() {}  // 为什么报表也在里面?
}

// ✅ 单一职责
class UserService { void create() {} void delete() {} }
class EmailService { void send() {} }
class ReportService { void generate() {} }

优先依赖接口

这样改实现类时调用方不用动:

java
// ✅ 依赖接口
private final UserRepository userRepository; // 接口
public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
}

// ❌ 依赖具体实现
private final JdbcUserRepository userRepository; // 改成 MyBatis 就得改 Service

减少 null 的使用

null 是万恶之源,尽量避免。

用 Optional

java
// ❌ 返回 null,调用方稍不留神就 NPE
public User findById(Long id) {
    return userRepository.findById(id).orElse(null);
}

// ✅ 返回 Optional,让调用方必须处理
public Optional<User> findById(Long id) {
    return userRepository.findById(id);
}

用空集合代替 null

java
// ❌ 不要返回 null
public List<Order> findOrders(Long userId) {
    return null; // ❌
}

// ✅ 返回空集合
public List<Order> findOrders(Long userId) {
    return orders; // 返回 Collections.emptyList()
}

总结

规范落地的关键:

  1. 小步重构:每次改一点,保持测试通过
  2. 代码审查:review 时检查规范执行情况
  3. 工具辅助:用 Checkstyle、SpotBugs 自动检查
  4. 写好注释:解释"为什么",而不是"是什么"

代码是写给人看的,顺便让机器执行。

基于 VitePress 构建