Java COLA架构案例

wen java案例 2

本文目录导读:

Java COLA架构案例

  1. 项目结构
  2. 核心代码实现
  3. 配置文件
  4. 核心特性说明

我将为您创建一个基于COLA(Clean Object-oriented and Layered Architecture)架构的电商订单系统完整案例。

项目结构

cola-order-system
├── pom.xml
├── start
│   └── src/main/java/com/example/start
│       └── Application.java
├── adapter
│   ├── web
│   │   └── src/main/java/com/example/adapter/web
│   │       ├── controller/OrderController.java
│   │       └── common/Response.java
│   └── repository
│       └── src/main/java/com/example/adapter/repository
│           ├── OrderRepositoryImpl.java
│           └── assembler/OrderAssembler.java
├── app
│   └── src/main/java/com/example/app
│       ├── executor/OrderCreateCmdExe.java
│       ├── executor/OrderQueryExe.java
│       ├── service/OrderService.java
│       └── assembler/OrderDTOAssembler.java
├── domain
│   └── src/main/java/com/example/domain
│       ├── order/Order.java
│       ├── order/OrderItem.java
│       ├── order/OrderStatus.java
│       ├── order/OrderFactory.java
│       ├── gateway/OrderGateway.java
│       └── service/OrderDomainService.java
├── infrastructure
│   └── src/main/java/com/example/infrastructure
│       ├── config/MybatisConfig.java
│       ├── convertor/OrderConvertor.java
│       ├── mapper/OrderMapper.java
│       └── dataobject/OrderDO.java
└── client
    └── src/main/java/com/example/client
        ├── dto/OrderDTO.java
        ├── dto/OrderItemDTO.java
        ├── dto/command/OrderCreateCommand.java
        ├── dto/query/OrderQuery.java
        └── api/OrderServiceI.java

核心代码实现

1 Client模块 (API层)

// OrderServiceI.java
package com.example.client.api;
import com.example.client.dto.OrderDTO;
import com.example.client.dto.command.OrderCreateCommand;
import com.example.client.dto.query.OrderQuery;
public interface OrderServiceI {
    String createOrder(OrderCreateCommand command);
    OrderDTO getOrder(OrderQuery query);
}
// OrderCreateCommand.java
package com.example.client.dto.command;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
public class OrderCreateCommand {
    @NotNull(message = "用户ID不能为空")
    private Long userId;
    @NotNull(message = "订单项不能为空")
    private List<OrderItemCommand> orderItems;
    private String couponCode;
    private String address;
    @Data
    public static class OrderItemCommand {
        @NotNull(message = "商品ID不能为空")
        private Long productId;
        @NotNull(message = "商品数量不能为空")
        private Integer quantity;
        private BigDecimal price;
    }
}
// OrderDTO.java
package com.example.client.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Data
public class OrderDTO {
    private String orderId;
    private Long userId;
    private BigDecimal totalAmount;
    private BigDecimal discountAmount;
    private BigDecimal payAmount;
    private String status;
    private Date createTime;
    private List<OrderItemDTO> orderItems;
}

2 Domain模块 (领域层)

// Order.java
package com.example.domain.order;
import lombok.Getter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Getter
public class Order {
    private String orderId;
    private Long userId;
    private BigDecimal totalAmount;
    private BigDecimal discountAmount;
    private BigDecimal payAmount;
    private OrderStatus status;
    private List<OrderItem> orderItems;
    public Order() {
        this.orderId = UUID.randomUUID().toString().replace("-", "");
        this.status = OrderStatus.CREATED;
        this.orderItems = new ArrayList<>();
        this.totalAmount = BigDecimal.ZERO;
        this.discountAmount = BigDecimal.ZERO;
    }
    public void addItem(Long productId, Integer quantity, BigDecimal price) {
        OrderItem item = new OrderItem(productId, quantity, price);
        this.orderItems.add(item);
        this.totalAmount = this.totalAmount.add(item.getTotalPrice());
    }
    public void applyDiscount(BigDecimal discount) {
        if (discount.compareTo(this.totalAmount) > 0) {
            throw new IllegalArgumentException("折扣金额不能超过订单总额");
        }
        this.discountAmount = discount;
        this.payAmount = this.totalAmount.subtract(discount);
    }
    public void confirm() {
        if (this.status != OrderStatus.CREATED) {
            throw new IllegalStateException("订单状态不允许确认");
        }
        this.status = OrderStatus.CONFIRMED;
    }
    public void cancel() {
        if (this.status == OrderStatus.COMPLETED) {
            throw new IllegalStateException("已完成订单不能取消");
        }
        this.status = OrderStatus.CANCELLED;
    }
    public void complete() {
        if (this.status != OrderStatus.CONFIRMED) {
            throw new IllegalStateException("订单未确认不能完成");
        }
        this.status = OrderStatus.COMPLETED;
    }
}
// OrderFactory.java
package com.example.domain.order;
import com.example.domain.gateway.OrderGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class OrderFactory {
    @Autowired
    private OrderGateway orderGateway;
    public Order createOrder(Long userId) {
        Order order = new Order();
        order.initUser(userId);
        return order;
    }
    public Order getOrder(String orderId) {
        return orderGateway.findByOrderId(orderId);
    }
}
// OrderDomainService.java
package com.example.domain.service;
import com.example.domain.order.Order;
import com.example.domain.gateway.OrderGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Service
public class OrderDomainService {
    @Autowired
    private OrderGateway orderGateway;
    public void createOrder(Order order) {
        orderGateway.save(order);
    }
    public void cancelOrder(String orderId, String operator) {
        Order order = orderGateway.findByOrderId(orderId);
        if (order == null) {
            throw new IllegalArgumentException("订单不存在");
        }
        order.cancel();
        orderGateway.save(order);
    }
    public BigDecimal calculateDiscount(Order order, String couponCode) {
        // 简单折扣逻辑:优惠码折扣10%
        if ("SAVE10".equals(couponCode)) {
            return order.getTotalAmount().multiply(new BigDecimal("0.1"));
        }
        return BigDecimal.ZERO;
    }
}

3 App模块 (应用层)

// OrderService.java
package com.example.app.service;
import com.example.client.api.OrderServiceI;
import com.example.client.dto.OrderDTO;
import com.example.client.dto.command.OrderCreateCommand;
import com.example.client.dto.query.OrderQuery;
import com.example.app.executor.OrderCreateCmdExe;
import com.example.app.executor.OrderQueryExe;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderService implements OrderServiceI {
    @Autowired
    private OrderCreateCmdExe orderCreateCmdExe;
    @Autowired
    private OrderQueryExe orderQueryExe;
    @Override
    public String createOrder(OrderCreateCommand command) {
        return orderCreateCmdExe.execute(command);
    }
    @Override
    public OrderDTO getOrder(OrderQuery query) {
        return orderQueryExe.execute(query);
    }
}
// OrderCreateCmdExe.java
package com.example.app.executor;
import com.example.client.dto.command.OrderCreateCommand;
import com.example.domain.order.Order;
import com.example.domain.order.OrderFactory;
import com.example.domain.service.OrderDomainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class OrderCreateCmdExe {
    @Autowired
    private OrderFactory orderFactory;
    @Autowired
    private OrderDomainService orderDomainService;
    @Transactional
    public String execute(OrderCreateCommand command) {
        // 1. 创建订单实体
        Order order = orderFactory.createOrder(command.getUserId());
        // 2. 添加订单项
        command.getOrderItems().forEach(item -> 
            order.addItem(item.getProductId(), item.getQuantity(), item.getPrice())
        );
        // 3. 计算折扣
        if (command.getCouponCode() != null) {
            BigDecimal discount = orderDomainService.calculateDiscount(order, command.getCouponCode());
            order.applyDiscount(discount);
        }
        // 4. 保存订单
        orderDomainService.createOrder(order);
        return order.getOrderId();
    }
}

4 Adapter模块 (适配层)

// OrderController.java
package com.example.adapter.web.controller;
import com.example.client.api.OrderServiceI;
import com.example.client.dto.OrderDTO;
import com.example.client.dto.command.OrderCreateCommand;
import com.example.client.dto.query.OrderQuery;
import com.example.adapter.web.common.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    @Autowired
    private OrderServiceI orderService;
    @PostMapping
    public Response<String> createOrder(@RequestBody OrderCreateCommand command) {
        String orderId = orderService.createOrder(command);
        return Response.success(orderId);
    }
    @GetMapping("/{orderId}")
    public Response<OrderDTO> getOrder(@PathVariable String orderId) {
        OrderQuery query = new OrderQuery();
        query.setOrderId(orderId);
        OrderDTO order = orderService.getOrder(query);
        return Response.success(order);
    }
}
// OrderRepositoryImpl.java
package com.example.adapter.repository;
import com.example.domain.gateway.OrderGateway;
import com.example.domain.order.Order;
import com.example.adapter.repository.assembler.OrderAssembler;
import com.example.infrastructure.convertor.OrderConvertor;
import com.example.infrastructure.mapper.OrderMapper;
import com.example.infrastructure.dataobject.OrderDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class OrderRepositoryImpl implements OrderGateway {
    @Autowired
    private OrderMapper orderMapper;
    @Override
    public void save(Order order) {
        OrderDO orderDO = OrderConvertor.toDataObject(order);
        orderMapper.insert(orderDO);
    }
    @Override
    public Order findByOrderId(String orderId) {
        OrderDO orderDO = orderMapper.findByOrderId(orderId);
        return OrderAssembler.toEntity(orderDO);
    }
    @Override
    public void update(Order order) {
        OrderDO orderDO = OrderConvertor.toDataObject(order);
        orderMapper.update(orderDO);
    }
}

5 Infrastructure模块 (基础设施层)

// OrderMapper.java
package com.example.infrastructure.mapper;
import com.example.infrastructure.dataobject.OrderDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface OrderMapper {
    int insert(OrderDO orderDO);
    OrderDO findByOrderId(@Param("orderId") String orderId);
    int update(OrderDO orderDO);
}
// OrderConvertor.java
package com.example.infrastructure.convertor;
import com.example.domain.order.Order;
import com.example.domain.order.OrderItem;
import com.example.infrastructure.dataobject.OrderDO;
public class OrderConvertor {
    public static OrderDO toDataObject(Order order) {
        if (order == null) {
            return null;
        }
        OrderDO orderDO = new OrderDO();
        orderDO.setOrderId(order.getOrderId());
        orderDO.setUserId(order.getUserId());
        orderDO.setTotalAmount(order.getTotalAmount());
        orderDO.setDiscountAmount(order.getDiscountAmount());
        orderDO.setPayAmount(order.getPayAmount());
        orderDO.setStatus(order.getStatus().getCode());
        return orderDO;
    }
}

配置文件

<!-- pom.xml -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>cola-order-system</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <modules>
        <module>start</module>
        <module>adapter</module>
        <module>app</module>
        <module>domain</module>
        <module>infrastructure</module>
        <module>client</module>
    </modules>
</project>
# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/order_db
    username: root
    password: root
  mybatis:
    mapper-locations: classpath:mapper/*.xml
    type-aliases-package: com.example.infrastructure.dataobject
server:
  port: 8080

核心特性说明

1 依赖方向

  • 外层依赖内层,内层不依赖外层
  • 领域层完全不依赖任何框架
  • 通过接口(Interface)实现依赖倒置

2 模块职责

  1. Client层:定义API接口和DTO
  2. App层:用例编排、事务管理、日志
  3. Domain层:核心业务逻辑、领域模型
  4. Infrastructure层:技术实现细节
  5. Adapter层:接口适配、数据转换

3 关键设计原则

// 1. 依赖倒置
public interface OrderGateway {
    void save(Order order);
    Order findByOrderId(String orderId);
}
// 2. 聚合根设计
@Getter
public class Order {
    private String orderId;
    private List<OrderItem> items;
    public void addItem(OrderItem item) {
        // 业务规则校验
        this.items.add(item);
        this.totalAmount = calculateTotalAmount();
    }
}
// 3. 领域服务
@Service
public class OrderDomainService {
    // 跨聚合的业务逻辑
}

这个案例展示了COLA架构的核心思想和实践方式,通过分层架构实现了业务与技术细节的解耦,使得系统更加清晰、可维护和可扩展。

抱歉,评论功能暂时关闭!