디자인 패턴(1): DDD 도메인 기반 디자인

  • DDD는 건축에 초점을 맞추고 비즈니스에 빛을 비춥니다! – 모놀리식 아키텍처의 빠른 검증
  • DDD 디자인 패턴
    • 빈혈 모델
    • 충혈 모델
    • 부식 방지층
  • DDD 4계층 아키텍처 사양
  • DDD 모놀리식 아키텍처 및 마이크로서비스 아키텍처 격리
    • 로컬 단일 SPI 플러그 가능 확장 비즈니스 모델
    • Nacos 플러그형 확장 비즈니스 모델 - 서비스 코드로서의 서비스 이름
  • DDD 명확한 아키텍처 – 도메인 재사용을 실현하기 위한 도메인 웨어하우스 구축

iQiyi의 팁 비즈니스에서 DDD(Domain-Driven Design) 실행

https://blog.csdn.net/weixin_45583158/article/details/114312926

DDD는 건축에 초점을 맞추고 비즈니스에 빛을 비춥니다! — 모놀리식 아키텍처의 빠른 검증

여기에 이미지 설명 삽입

DDD 디자인 패턴

1. 빈혈 모델

  • POJO는 비즈니스가 없습니다.
  • 사업은 서비스로 이양

2. 충혈 모델

  • DAO 책임 및 비즈니스 매핑
  • DO는 DB 매핑을 담당합니다.

3. 부식 방지층

  • BusiSafeService의 캡슐화 및 캡슐화
  • Kafak은 AduitMessageProducer를 캡슐화합니다.
  • 금액 계산AccountTransferService
  • 단일 개체의 상태 동작을 엔터티(Entity)로 캡슐화
  • 도메인 서비스는 다중 엔터티 논리를 캡슐화합니다.

변경 전

public class PaymentController{
    
    
    private PayService payService;
    public Result pay(String merchantAccount,BigDecimal amount){
    
    
        Long userId = (Long) session.getAttribute("userId");
  return payService.pay(userId, merchantAccount, amount);
    }
}

public class PayServiceImpl extends PayService{
    
    
    private AccountDao accountDao;//操作数据库
    private KafkaTemplate<String, String> kafkaTemplate;//操作kafka
    private RiskCheckService riskCheckService;//风控微服务接口
    
    public Result pay(Long userId,String merchantAccount,BigDecimal amount){
    
    
        // 1. 从数据库读取数据
        AccountDO clientDO = accountDAO.selectByUserId(userId);
        AccountDO merchantDO =
        accountDAO.selectByAccountNumber(merchantAccount);
        // 2. 业务参数校验
        if (amount>(clientDO.getAvailable()) {
    
    
         throw new NoMoneyException();
        }
        // 3. 调用风控微服务
        RiskCode riskCode = riskCheckService.checkPayment(...);
        // 4. 检查交易合法性
        if("0000"!= riskCode){
    
    
            throw new InvalideOperException();
        }
        // 5. 计算新值,并且更新字段
        BigDecimal newSource = clientDO.getAvailable().subtract(amount);
        BigDecimal newTarget = merchantDO.getAvailable().add(amount);
        clientDO.setAvailable(newSource);
        merchantDO.setAvailable(newTarget);
        // 6. 更新到数据库
        accountDAO.update(clientDO);
        accountDAO.update(merchantDO);
        // 7. 发送审计消息
        String message = sourceUserId + "," + targetAccountNumber + "," + targetAmount;
        kafkaTemplate.send(TOPIC_AUDIT_LOG, message);
        return Result.SUCCESS;
    }
}

변경 후

public class PaymentController{
    
    
    private PayService payService;
    public Result pay(String merchantAccount,BigDecimal amount){
    
    
        Long userId = (Long) session.getAttribute("userId");
  return payService.pay(userId, merchantAccount, amount);
    }
}

public class PayServiceImpl extends PayService{
    
    
    private AccountRepository accountRepository;
    private AuditMessageProducer auditMessageProducer;
    private BusiSafeService busiSafeService;
    private AccountTransferService accountTransferService;
    
    public Result pay(Long userId,String merchantAccount,BigDecimal amount){
    
    
        // 参数校验
        Money money = new Money(amount);
        UserId clientId = new UserId(userId);
        AccountNumber merchantNumber = new AccountNumber(merchantAccount);
        // 读数据
        Account clientAccount = accountRepository.find(clientId);
        Account merAccount = accountRepository.find(merchantNumber);
        // 交易检查
        Result preCheck =  busiSafeService.checkBusi(clientAccount,merAccount,money);
        if(preCheck != Result.SUCCESS)return Result.REJECT;
        // 业务逻辑
  accountTransferService.transfer(clientAccount,merAccount,money);
        // 保存数据
        accountRepository.save(clientAccount);
        accountRepository.save(merAccount);
        // 发送审计消息
        AuditMessage message = new AuditMessage(clientAccount, merAccount,money);
  auditMessageProducer.send(message);
        return Result.SUCCESS;
    }
}

DDD 4계층 아키텍처 사양

  1. 도메인 레이어: 시스템의 핵심으로, 외부 종속성 없이 순수하게 비즈니스 기능을 표현합니다.
  2. 애플리케이션 계층: 도메인 개체를 조정하고 비즈니스 시나리오를 구성 및 구성하며 도메인 계층에만 의존합니다.
  3. 사용자 인터페이스(User Interface): 사용자와의 상호 작용을 담당합니다. 사용자 요청을 이해하고 사용자 응답을 반환합니다. 애플리케이션 계층에만 의존
  4. 인프라 계층: 비즈니스와 데이터의 분리. 도메인 계층에 대한 지속성 서비스 및 기타 계층에 대한 일반 기능 제공

여기에 이미지 설명 삽입

어댑터는 각 서비스 계층을 격리합니다.
여기에 이미지 설명 삽입

DDD 모놀리식 아키텍처 및 마이크로서비스 아키텍처 격리

//TODO 单体架构与微服务架构只需要切换一个服务实现类即可,对各领域的核心是没有影响的。。
//@Resource(name = "LocalAsyncBusiService") //基于SPI实现的单体架构消息处理服务
@Resource(name = "NacosAsyncBusiService") //基于Nacos实现的微服务消息处理服务
private AsyncBusiService asyncBusiService;

로컬 단일 SPI 플러그 가능 확장 비즈니스 모델

@Component
public class BusiServiceRepositoryimpl implements BusiServiceRepository {
    
    

    private List<GsService> busiServices = new ArrayList<>();

    @PostConstruct
    public void loadBusiServices() {
    
    
        if (busiServices.isEmpty()) {
    
    
            final ServiceLoader<GsService> gsServices = ServiceLoader.load(GsService.class);
            final Iterator<GsService> iterator = gsServices.iterator();
            while (iterator.hasNext()) {
    
    
                busiServices.add(iterator.next());
            }
        }
    }

    public GsService getGsService(String serviceCode) {
    
    
        for (GsService gsService : busiServices) {
    
    
            if (serviceCode.equals(gsService.serviceCode())) {
    
    
                return gsService;
            }
        }
        return null;
    }
}

Nacos 플러그형 확장 비즈니스 모델 - 서비스 코드로서의 서비스 이름

@Resource
private DiscoveryClient discoveryClient;

//1、去Nacos上获取服务实例。
List<ServiceInstance> instances = discoveryClient.getInstances(serviceCode);
//1-1、如果服务不存在,直接返回不支持的serviceCode
if(null == instances || instances.isEmpty()){
    
    
    logger.error("ServiceCode["+serviceCode+"] is not support yet.");
    return;
}
StringBuffer requestUrl = new StringBuffer("http://");
ServiceInstance serviceInstance;
//随机找一个实例
if(instances.size()==1){
    
    
    serviceInstance = instances.get(0);
}else{
    
    
    Random random = new Random();
    int index = random.nextInt(instances.size());
    serviceInstance = instances.get(index);
}
//接口路径固定请求 SERVICE_SUFFIX
requestUrl.append(serviceInstance.getHost()).append(":").append(serviceInstance.getPort()).append(SERVICE_SUFFIX);

DDD 명확한 아키텍처 – 도메인 재사용을 실현하기 위한 도메인 웨어하우스 구축

https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/

여기에 이미지 설명 삽입

구체화된 형태의
여기에 이미지 설명 삽입
메시지 계약 계층: 많은 MVC 프로젝트의 개발 과정에서 데이터를 전송하는 POJO는 DTO, VO, BO, DO 등과 같은 다양한 Object로 구분될 것이며, 서로 다른 방식이 사용된다는 것이 지속적으로 규정되어 있습니다. 각 기술 수준 개체, 그 목적은 각 계층의 데이터가 더 순수하고 외부 데이터의 영향을 줄이도록 노력하는 것입니다.

Je suppose que tu aimes

Origine blog.csdn.net/menxu_work/article/details/128565695
conseillé
Classement