Java记录类与Sealed类深度实战:构建类型安全的领域驱动设计系统

2025-11-08 0 929

一、现代Java类型系统的革命性演进

Java 14引入的记录类(Record)和Java 17引入的Sealed类(密封类)彻底改变了我们构建领域模型的方式。这些特性结合模式匹配,为构建类型安全、表达力强的领域驱动设计系统提供了强大工具。

新旧特性对比:

特性 传统方式 记录类+Sealed类
不可变对象 大量样板代码 自动生成所有方法
类型安全 运行时检查 编译时保证
模式匹配 instanceof + 强制转换 类型模式直接解构
可维护性 容易出错 编译器辅助验证

二、记录类深度解析与高级用法

1. 基础记录类定义

// 基础记录类 - 自动生成constructor, getters, equals, hashCode, toString
public record User(
    Long id,
    String username,
    String email,
    LocalDateTime createdAt
) {
    // 紧凑构造函数 - 用于验证逻辑
    public User {
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("ID必须为正数");
        }
        if (username == null || username.trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        email = email == null ? "" : email.toLowerCase();
    }
    
    // 自定义方法
    public boolean isEmailVerified() {
        return !email.isEmpty();
    }
    
    // 静态工厂方法
    public static User of(String username, String email) {
        return new User(null, username, email, LocalDateTime.now());
    }
}

// 使用示例
User user = new User(1L, "john_doe", "john@example.com", LocalDateTime.now());
User createdUser = User.of("jane_doe", "jane@example.com");

2. 记录类与接口组合

// 定义领域接口
public interface DomainEntity {
    Long getId();
    LocalDateTime getCreatedAt();
    default boolean isNew() {
        return getId() == null;
    }
}

// 记录类实现接口
public record Product(
    Long id,
    String name,
    BigDecimal price,
    ProductCategory category,
    LocalDateTime createdAt
) implements DomainEntity {
    
    // 验证业务规则
    public Product {
        if (price == null || price.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("价格必须为非负数");
        }
        if (category == null) {
            throw new IllegalArgumentException("产品分类不能为空");
        }
    }
    
    // 业务方法
    public Product applyDiscount(BigDecimal discountRate) {
        if (discountRate.compareTo(BigDecimal.ZERO)  0) {
            throw new IllegalArgumentException("折扣率必须在0-1之间");
        }
        BigDecimal newPrice = price.multiply(BigDecimal.ONE.subtract(discountRate));
        return new Product(id, name, newPrice, category, createdAt);
    }
}

3. 记录类的高级模式

// 嵌套记录类
public record Order(
    Long id,
    Customer customer,
    List items,
    OrderStatus status,
    LocalDateTime orderDate
) {
    
    // 计算属性
    public BigDecimal getTotalAmount() {
        return items.stream()
            .map(OrderItem::getSubtotal)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    public record OrderItem(
        Product product,
        Integer quantity,
        BigDecimal unitPrice
    ) {
        public OrderItem {
            if (quantity == null || quantity <= 0) {
                throw new IllegalArgumentException("数量必须为正数");
            }
            if (unitPrice == null || unitPrice.compareTo(BigDecimal.ZERO) < 0) {
                throw new IllegalArgumentException("单价必须为非负数");
            }
        }
        
        public BigDecimal getSubtotal() {
            return unitPrice.multiply(BigDecimal.valueOf(quantity));
        }
    }
}

// 使用构建器模式增强记录类
public class UserBuilder {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createdAt = LocalDateTime.now();
    
    public UserBuilder id(Long id) {
        this.id = id;
        return this;
    }
    
    public UserBuilder username(String username) {
        this.username = username;
        return this;
    }
    
    public UserBuilder email(String email) {
        this.email = email;
        return this;
    }
    
    public User build() {
        return new User(id, username, email, createdAt);
    }
}

三、Sealed类实战:构建类型安全的领域模型

1. 密封接口与实现

// 定义密封接口
public sealed interface PaymentMethod 
    permits CreditCard, BankTransfer, DigitalWallet {
    
    String getAccountNumber();
    BigDecimal getBalance();
    PaymentResult processPayment(BigDecimal amount);
}

// 具体的支付方式实现
public record CreditCard(
    String cardNumber,
    String cardHolder,
    LocalDate expiryDate,
    String cvv,
    BigDecimal balance
) implements PaymentMethod {
    
    public String getAccountNumber() {
        return cardNumber;
    }
    
    public PaymentResult processPayment(BigDecimal amount) {
        if (balance.compareTo(amount) < 0) {
            return new PaymentResult(false, "余额不足");
        }
        // 信用卡支付逻辑
        return new PaymentResult(true, "支付成功");
    }
}

public record BankTransfer(
    String accountNumber,
    String bankName,
    String accountHolder,
    BigDecimal balance
) implements PaymentMethod {
    
    public PaymentResult processPayment(BigDecimal amount) {
        // 银行转账逻辑
        return new PaymentResult(true, "转账处理中");
    }
}

public record DigitalWallet(
    String walletId,
    String provider,
    BigDecimal balance
) implements PaymentMethod {
    
    public String getAccountNumber() {
        return walletId;
    }
    
    public PaymentResult processPayment(BigDecimal amount) {
        // 数字钱包支付逻辑
        return new PaymentResult(true, "钱包支付成功");
    }
}

2. 密封类与模式匹配结合

// 支付处理服务
@Service
public class PaymentProcessingService {
    
    public PaymentResponse processOrderPayment(Order order, PaymentMethod paymentMethod) {
        PaymentResult result = paymentMethod.processPayment(order.getTotalAmount());
        
        // 使用模式匹配处理不同类型的支付结果
        return switch (paymentMethod) {
            case CreditCard card -> handleCreditCardPayment(card, result, order);
            case BankTransfer transfer -> handleBankTransfer(transfer, result, order);
            case DigitalWallet wallet -> handleDigitalWallet(wallet, result, order);
            // 不需要default分支,编译器知道所有情况都已覆盖
        };
    }
    
    private PaymentResponse handleCreditCardPayment(
        CreditCard card, PaymentResult result, Order order) {
        
        if (result.success()) {
            // 发送信用卡支付确认
            notificationService.sendCreditCardConfirmation(card.cardHolder(), order);
        }
        return new PaymentResponse(result.success(), result.message(), "CREDIT_CARD");
    }
    
    private PaymentResponse handleBankTransfer(
        BankTransfer transfer, PaymentResult result, Order order) {
        
        // 生成银行转账参考号
        String referenceNumber = generateBankReference(transfer, order);
        return new PaymentResponse(result.success(), referenceNumber, "BANK_TRANSFER");
    }
    
    private PaymentResponse handleDigitalWallet(
        DigitalWallet wallet, PaymentResult result, Order order) {
        
        if (result.success()) {
            // 记录钱包交易
            walletService.recordTransaction(wallet.walletId(), order.getTotalAmount());
        }
        return new PaymentResponse(result.success(), result.message(), "DIGITAL_WALLET");
    }
}

四、DDD领域建模实战:电商系统完整案例

1. 值对象建模

// 地址值对象
public record Address(
    String street,
    String city,
    String state,
    String zipCode,
    String country
) {
    public Address {
        Objects.requireNonNull(street, "街道不能为空");
        Objects.requireNonNull(city, "城市不能为空");
        Objects.requireNonNull(country, "国家不能为空");
        
        if (street.trim().isEmpty()) {
            throw new IllegalArgumentException("街道不能为空");
        }
    }
    
    public String getFullAddress() {
        return String.format("%s, %s, %s %s, %s", street, city, state, zipCode, country);
    }
    
    public boolean isDomestic() {
        return "US".equals(country);
    }
}

// 货币值对象
public record Money(
    BigDecimal amount,
    Currency currency
) implements Comparable {
    
    public Money {
        Objects.requireNonNull(amount, "金额不能为空");
        Objects.requireNonNull(currency, "货币类型不能为空");
        
        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("金额不能为负数");
        }
        // 标准化金额精度
        amount = amount.setScale(currency.getDefaultFractionDigits(), RoundingMode.HALF_EVEN);
    }
    
    public Money add(Money other) {
        validateSameCurrency(other);
        return new Money(amount.add(other.amount), currency);
    }
    
    public Money subtract(Money other) {
        validateSameCurrency(other);
        return new Money(amount.subtract(other.amount), currency);
    }
    
    public Money multiply(BigDecimal multiplier) {
        return new Money(amount.multiply(multiplier), currency);
    }
    
    private void validateSameCurrency(Money other) {
        if (!this.currency.equals(other.currency)) {
            throw new IllegalArgumentException("货币类型不匹配");
        }
    }
    
    @Override
    public int compareTo(Money other) {
        validateSameCurrency(other);
        return this.amount.compareTo(other.amount);
    }
}

2. 聚合根设计

// 订单聚合根
public record OrderAggregate(
    OrderId id,
    CustomerId customerId,
    Address shippingAddress,
    List orderLines,
    OrderStatus status,
    Money totalAmount,
    LocalDateTime createdDate,
    LocalDateTime updatedDate
) {
    
    public OrderAggregate {
        Objects.requireNonNull(id, "订单ID不能为空");
        Objects.requireNonNull(customerId, "客户ID不能为空");
        Objects.requireNonNull(orderLines, "订单项不能为空");
        Objects.requireNonNull(status, "订单状态不能为空");
        
        if (orderLines.isEmpty()) {
            throw new IllegalArgumentException("订单必须包含至少一个订单项");
        }
        
        // 计算总金额
        totalAmount = calculateTotalAmount(orderLines);
    }
    
    private static Money calculateTotalAmount(List orderLines) {
        return orderLines.stream()
            .map(OrderLine::getLineTotal)
            .reduce(Money.zero(Currency.getInstance("USD")), Money::add);
    }
    
    // 领域命令
    public OrderAggregate applyDiscount(Discount discount) {
        Money discountedAmount = discount.applyTo(totalAmount);
        return new OrderAggregate(
            id, customerId, shippingAddress, orderLines, 
            status, discountedAmount, createdDate, LocalDateTime.now()
        );
    }
    
    public OrderAggregate cancel() {
        if (status == OrderStatus.SHIPPED || status == OrderStatus.DELIVERED) {
            throw new IllegalStateException("已发货或已送达的订单不能取消");
        }
        return new OrderAggregate(
            id, customerId, shippingAddress, orderLines,
            OrderStatus.CANCELLED, totalAmount, createdDate, LocalDateTime.now()
        );
    }
}

// 订单项值对象
public record OrderLine(
    ProductId productId,
    String productName,
    Integer quantity,
    Money unitPrice
) {
    public Money getLineTotal() {
        return unitPrice.multiply(BigDecimal.valueOf(quantity));
    }
}

五、模式匹配高级技巧与实战

1. 类型模式与记录模式

// 复杂的模式匹配示例
public class OrderProcessor {
    
    public ProcessingResult processOrder(OrderAggregate order) {
        return switch (order.status()) {
            case OrderStatus.PENDING pending -> processPendingOrder(order, pending);
            case OrderStatus.PAID paid -> processPaidOrder(order, paid);
            case OrderStatus.SHIPPED shipped -> processShippedOrder(order, shipped);
            case OrderStatus.CANCELLED cancelled -> processCancelledOrder(order, cancelled);
            case OrderStatus.DELIVERED delivered -> processDeliveredOrder(order, delivered);
        };
    }
    
    // 记录模式 - 解构记录类
    public String formatOrderSummary(Object order) {
        return switch (order) {
            case OrderAggregate(var id, var customerId, var address, 
                               var orderLines, var status, var totalAmount, 
                               var createdDate, var updatedDate) -> 
                String.format("订单 %s - 总金额: %s - 状态: %s", 
                    id.value(), totalAmount, status);
            
            case null -> "订单为空";
            default -> "未知订单类型";
        };
    }
    
    // 守卫模式
    public boolean canApplyDiscount(OrderAggregate order, Discount discount) {
        return switch (order) {
            case OrderAggregate o when o.totalAmount().compareTo(Money.of(100, "USD")) > 0 ->
                discount.isApplicableToLargeOrders();
            
            case OrderAggregate o when o.orderLines().size() > 5 ->
                discount.isApplicableToMultiItemOrders();
            
            default -> discount.isApplicable();
        };
    }
}

// 嵌套模式匹配
public class ShippingCalculator {
    
    public Money calculateShippingCost(OrderAggregate order) {
        return switch (order) {
            case OrderAggregate(_, _, Address(_, _, _, _, var country), 
                               var orderLines, _, var totalAmount, _, _) 
                when "US".equals(country) -> {
                
                if (totalAmount.compareTo(Money.of(50, "USD")) > 0) {
                    yield Money.zero(Currency.getInstance("USD")); // 免费配送
                } else if (orderLines.size() > 3) {
                    yield Money.of(5.99, "USD"); // 多件商品优惠配送
                } else {
                    yield Money.of(9.99, "USD"); // 标准配送
                }
            }
            
            case OrderAggregate(_, _, Address(_, _, _, _, var country), _, _, _, _) 
                when !"US".equals(country) -> {
                // 国际配送逻辑
                yield Money.of(29.99, "USD");
            }
            
            default -> throw new IllegalArgumentException("无法计算配送费用");
        };
    }
}

六、性能优化与最佳实践

1. 记录类性能优势

@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
public class RecordPerformanceBenchmark {
    
    private List recordUsers;
    private List legacyUsers;
    
    @Setup
    public void setup() {
        recordUsers = IntStream.range(0, 1000)
            .mapToObj(i -> new User((long) i, "user" + i, "user" + i + "@test.com", LocalDateTime.now()))
            .toList();
            
        legacyUsers = IntStream.range(0, 1000)
            .mapToObj(i -> new LegacyUser((long) i, "user" + i, "user" + i + "@test.com", LocalDateTime.now()))
            .toList();
    }
    
    @Benchmark
    public long recordHashCodePerformance() {
        return recordUsers.stream()
            .mapToInt(User::hashCode)
            .sum();
    }
    
    @Benchmark
    public long legacyHashCodePerformance() {
        return legacyUsers.stream()
            .mapToInt(LegacyUser::hashCode)
            .sum();
    }
}

// 传统Java类对比
class LegacyUser {
    private final Long id;
    private final String username;
    private final String email;
    private final LocalDateTime createdAt;
    
    // 大量样板代码...
    // constructors, getters, equals, hashCode, toString
}

2. 最佳实践总结

  • 记录类适用场景:数据传输对象、值对象、不可变配置、方法返回多个值
  • Sealed类适用场景:定义有限的继承层次、状态机、表达式树、领域事件
  • 性能优势:减少内存占用、更快的hashCode/equals、更好的内联优化
  • 设计原则:优先使用记录类表示数据、使用密封类限制继承、结合模式匹配处理多态

3. 迁移策略建议

// 迁移步骤示例
public class MigrationStrategy {
    // 1. 识别适合的记录类候选
    // - 主要是数据的类
    // - 不可变对象
    // - 需要值语义的类
    
    // 2. 识别适合的密封类候选  
    // - 有限的子类层次
    // - 需要编译时类型安全的场景
    // - 模式匹配的目标类型
    
    // 3. 渐进式迁移
    // - 从核心领域模型开始
    // - 保持向后兼容性
    // - 逐步替换传统实现
}

总结与展望

Java记录类和Sealed类的引入标志着Java语言在现代化道路上的重要里程碑:

  • 开发效率革命:大幅减少样板代码,提升开发速度
  • 类型安全增强:编译时保证,减少运行时错误
  • 领域表达力:更贴近业务语言的代码结构
  • 性能优化:更好的内存使用和运行时性能

未来发展方向:

  1. 更多语言特性与记录类/Sealed类的深度集成
  2. 框架和库对新型类的原生支持
  3. 更强大的模式匹配能力
  4. 工具链的持续优化和改进

掌握记录类和Sealed类不仅能够编写更简洁、更安全的代码,更重要的是能够构建更加健壮、更易维护的领域驱动设计系统,为复杂业务场景提供坚实的技术基础。

Java记录类与Sealed类深度实战:构建类型安全的领域驱动设计系统
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 java Java记录类与Sealed类深度实战:构建类型安全的领域驱动设计系统 https://www.taomawang.com/server/java/1399.html

下一篇:

已经没有下一篇了!

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务