設計パターン (1): DDD ドメイン駆動設計

  • DDD はアーキテクチャに重点を置き、ビジネスに重点を置いています。– モノリシックアーキテクチャによる迅速な検証
  • DDDデザインパターン
    • 貧血モデル
    • 充血モデル
    • 防食層
  • DDD 4 層アーキテクチャ仕様
  • DDD モノリシック アーキテクチャとマイクロサービス アーキテクチャの分離
    • ローカルの単一 SPI プラガブル拡張ビジネス モデル
    • Nacos プラガブル拡張機能のビジネス モデル - サービス コードとしてのサービス名
  • DDD 明確なアーキテクチャ – ドメイン ウェアハウスを構築してドメインの再利用を実現

iQiyiの投げ銭ビジネスにおけるドメイン駆動設計(DDD)の実践

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

DDD はアーキテクチャに重点を置き、ビジネスに重点を置いています。— モノリシックアーキテクチャによる迅速な検証

ここに画像の説明を挿入

DDDデザインパターン

1. 貧血モデル

  • POJOには用事がない
  • ビジネスはサービスに引き継がれます

2. 充血モデル

  • DAOの責任とビジネスマッピング
  • DO は DB マッピングを担当します

3. 防食層

  • BusiSafeService のカプセル化とカプセル化
  • Kafak は AduitMessageProducer をカプセル化します
  • 金額計算口座振替サービス
  • 単一オブジェクトの状態動作をエンティティ (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. ユーザー インターフェイス (ユーザー インターフェイス): ユーザーとの対話を担当します。ユーザーのリクエストを理解し、ユーザーの応答を返します。アプリケーション層のみに依存する
  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 などのさまざまなオブジェクトに分割され、異なるメソッドが使用されることが常に規定されています。各技術レベルの目的、その目的は、各層のデータがより純粋であることを保証し、外部データの影響を軽減することを試みることです。

おすすめ

転載: blog.csdn.net/menxu_work/article/details/128565695