文档首页> 云计算> Java面向对象思想解析:如何编写出高质量的代码

Java面向对象思想解析:如何编写出高质量的代码

发布时间:2025-11-01 00:13       

以下内容落地、务实、可直接复用;目标是把“面向对象”从口号变成可交付的工程实践。🙂

一、核心结论(直说)

  • 以领域建模驱动代码结构:先讲业务语言,再写类;拒绝“表结构即模型”的贫血对象。
  • 高内聚、低耦合:类只做一件事,把变化点关进小房间。
  • 显式不变式:对象创建即校验,非法状态不落地。
  • 组合优先于继承:继承只用于“是一个”,其余用组合与委托。
  • 接口编程:依赖抽象而不是具体实现,方便替换与测试。
  • 面向用例而非层堆砌:以“应用服务 → 领域模型 → 基础设施”的最小骨架交付价值。

二、设计基准(可量化)

维度 目标 快速判断
内聚 单一职责 类名能否一句话说清?方法是否超过7±2?
耦合 依赖倒置 业务不直接依赖外部SDK;通过接口/端口适配
可测性 单测先行 领域层无需Spring环境即可测
可演进 封装变化 第三方依赖、规则频繁变动处做“防腐层”
可读性 语义清晰 用领域词汇命名,拒绝Manager/Util套娃

三、建模抓手(DDD最小落地包)

  • 实体(Entity):有标识、会变;承担领域行为与不变式。
  • 值对象(Value Object):无标识、不可变;用于表达概念与校验。
  • 聚合(Aggregate):一致性边界;对外只暴露聚合根。
  • 领域服务:跨实体的业务规则;无状态。
  • 应用服务:编排用例;不写业务规则。

四、代码示例(Java 21+,利用 record/sealed/Pattern Matching)

// 值对象:不可变,创建即校验
public record Money(long cents) {
  public Money {
    if (cents < 0) throw new IllegalArgumentException("金额不能为负");
  }
  public Money add(Money other){ return new Money(this.cents + other.cents); }
  public boolean gte(Money other){ return this.cents >= other.cents; }
}

// 聚合根:封装不变式与行为
public final class Order {
  private final String id;
  private final List<OrderLine> lines = new ArrayList<>();
  private OrderStatus status = OrderStatus.CREATED;

  public Order(String id){ this.id = Objects.requireNonNull(id); }

  public void addLine(Product product, int qty){
    if (status != OrderStatus.CREATED) throw new IllegalStateException("非创建态不可加行");
    lines.add(new OrderLine(product, qty));
  }

  public Money total(){
    return lines.stream()
      .map(OrderLine::subtotal)
      .reduce(new Money(0), Money::add);
  }

  public void pay(Money paid){
    if (!paid.gte(total())) throw new IllegalArgumentException("实付不足");
    this.status = OrderStatus.PAID;
  }
}

// 组合优先:行项目组合值对象
record OrderLine(Product product, int qty){
  OrderLine {
    if (qty <= 0) throw new IllegalArgumentException("数量必须大于0");
  }
  Money subtotal(){ return new Money(product.price().cents() * qty); }
}

record Product(String id, Money price){}
enum OrderStatus { CREATED, PAID }

要点

  • 用 record 表达不可变值对象,天然线程安全。
  • 不变式写在构造器/工厂方法中;拒绝“先new,后校验”的脆弱流程。
  • 领域行为放进聚合根(如 pay),避免贫血模型。

五、演进策略(把变化关进小房间)

  • 接口 + 适配器:外部支付、存储、消息等,经由端口接口隔离;替换实现时应用层无感。
  • 策略模式:计价、风控、路由等规则高频变更点抽象为策略集合。
  • 防腐层:与遗留系统或三方SDK交互,做字段、异常、语义的双向转换。
  • 可观察性:领域事件 + 结构化日志,问题可回放。📈

六、代码评审清单(PR前自检)

  • 是否存在无校验的setters?(有就收口到构造/方法)
  • 是否把“用例编排”和“领域规则”混在Controller里?(拆)
  • 命名是否使用领域语言?(用户能读懂)
  • 是否为边界条件写了单测?(空集合、极值、并发)
  • 是否出现过度继承?能否改为组合?

七、最小流程图(从用例到交付)

graph LR
A[接收用例请求]-->B[应用服务编排]
B-->C[加载聚合根]
C-->D[执行领域行为:校验+状态变更]
D-->E[发布领域事件]
E-->F[持久化/外部依赖经端口适配器]
F-->G[返回结果与审计日志]

八、实践tips(真刀真枪)

  • 虚拟线程(Java 21):I/O密集型应用显著提升吞吐,但领域模型不应泄露线程细节
  • Pattern Matching for switch:简化业务规则分派,配合策略更干净。
  • Optional/Null Object:消灭NPE,语义明确。
  • 记录型事件:领域事件用 record,天然不可变,序列化友好。🚀

一句话收尾:用面向对象把“业务词汇”铸进代码,把变化隔离在边界,把规则写进对象——你的系统会更稳、更易测、更能迭代。