ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

DDD(Domain Driven Design) 领域驱动设计从理论到实践 八

2021-07-16 13:57:50  阅读:243  来源: 互联网

标签:Domain DomainEvent int Driven AbstractDomainEvent ValueObject Design extends def


…接上

六. 实践:战术设计

​     从某种意义上说,战略设计代表了计划能力,而战术设计代表了执行力。本节我们就来执行一下,因为本领域模型虽然并不复杂,但是如果把所有模型都贴出来也不太现实。笔者这里展示两个界限上下文的设计,只是个初稿,有很多不足,非常希望都到广大读者和专业人士的指正。

用户管理上下文

在这里插入图片描述
​ CML 代码:

BoundedContext userManagementContext implements userDomain {
    type = FEATURE
    domainVisionStatement = "User management from system view"
    implementationTechnology = "Java, SpringBoot"
    responsibilities = "User", "Role"
    knowledgeLevel = CONCRETE

    Aggregate User {
        responsibilities = "User"
        knowledgeLevel = CONCRETE
        securityZone "Internal"
        contentVolatility = NORMAL
        consistencyCriticality = HIGH
        securityCriticality = HIGH

        Entity User {
            aggregateRoot

            - UserID userId
            - Status userStatus
            - UserType userType
            - BasicProfile profile
            - List<Role> roles
            - UserQualify qualify
            - Account account
            DateTime registeredTime
            DateTime updatedTime

            def int UpdateUserProfile(userIdentification id) : write;
            def int CreateUser() : write [ ->CREATED ];
            def int DropUser() : write [ ->REMOVED ];
            def int ActivatedUser() : write [ ->ACTIVATED ];
            def int DeactivatedUSer() : write [ ACTIVATED -> DEACTIVATED ];
            def int UpdateUserRole();
            def User ReadUserProfile() : read-only;

            Repository UserRepository {
                @User get(@UserID id);
                List<@User> getAll();
            }
        }

        ValueObject UserID {
            long userId
        }

        ValueObject BasicProfile {
            String userName
            String password
            String cellPhone
            DateTime birthDate
            String mailAddress
            String alternativeMail
        }

        ValueObject Account {
            - UserID userId
            - List<VirtualCurrency> virtualCurr
        }

        abstract ValueObject VirtualCurrency {
            float amount
        }

        ValueObject Money extends VirtualCurrency {
            - Currency curr
            float mapping
            baseCurrency rmb
        }

        ValueObject Score extends VirtualCurrency {
            float ratio
            baseCurrency rmb
        }

        enum Currency {
            RMB,DOLLAR
        }

        enum UserType {
            USER, ROLEADMIN, DOMAINADMIN, SITEADMIN
        }

        enum Status {
            aggregateLifecycle
            ACTIVATED, DEACTIVATED, CREATED, REMOVED
        }

        abstract DomainEvent AbstractDomainEvent {
            DateTime timestamp
        }

        DomainEvent UserProfileChanged extends AbstractDomainEvent {}
        DomainEvent UserCreated extends AbstractDomainEvent {}
        DomainEvent UserRemoved extends AbstractDomainEvent {}
        DomainEvent UserActivated extends AbstractDomainEvent {}
        DomainEvent UserDeactivated extends AbstractDomainEvent {}
        DomainEvent UserRolesAsscioationChanged extends AbstractDomainEvent {}

    }

    Aggregate Role {
        responsibilities = "Role"
        knowledgeLevel = CONCRETE

        ValueObject Role {
            aggregateRoot

            - RoleType roleType  
            String desc
            - Status status
            - Rules defaultRule

            def int CreateRole();
            def int CreatedCustomedRole();
            def int UpdateRole();
            def int ActivatedRole();
            def int DeactivatedRole();
            def int DropRole();

        }

        enum RoleType {
            ORG, PARTNER, CHANNEL, MEMBER, CUSTOMED
        }

        DomainEvent RoleCreated extends AbstractDomainEvent {}
        DomainEvent RoleRemoved extends AbstractDomainEvent {}
        DomainEvent RoleActivated extends AbstractDomainEvent {}
        DomainEvent RoleDeactivated extends AbstractDomainEvent {}
        DomainEvent RoleProfileChanged extends AbstractDomainEvent {}

    }

    Aggregate UserQualify {
        responsibilities = "Role"
        knowledgeLevel = CONCRETE

        ValueObject UserQualify {
            aggregateRoot

            - Qualify qualify
            String desc
        }

        enum Qualify {
            DOCTOR,RESEARCHER,LIBRARIAN,OTHERS
        }

    }

}

UML :
在这里插入图片描述
​     把实体(Entity)和值对象(Value Object)在一致性边界之内组成聚合(Aggregate)乍看起来是一项比较简单和轻松的任务,但在DDD的众多战术指导中却是最难理解的。一个需要明确回答的关键问题是:聚合的不变条件和一致性边界究竟是什么?笔者本人也还没有这个水平来正确回答这个问题,个人的理解是聚合本身应该保证业务规则的不变性和一致性。

​     DDD本身主张小的聚合,因为一个聚合如果引入了太多对象时,整个对象的加载和更新操作将会变得很沉重。例如大的聚合在维护整体事务一致性上将会面临麻烦,从而限制了系统的性能和可伸缩性。

​     DDD推荐聚合的实现时遵循迪米特法则告诉非询问原则。前者强调最小知识,后者更为简单。

​     在上面所展示的用户管理上下文的实现中,这个上下文是由两个聚合组成的,分别是用户和角色。

订单与支付上下文

在这里插入图片描述
​ 这个上下文由两个聚合来组成,分别是订单和支付。

CML 代码:

BoundedContext orderContext implements businessDomain {
    type = FEATURE
    domainVisionStatement = "Orders Management"
    implementationTechnology = "Java, SpringBoot"
    knowledgeLevel = CONCRETE

    Aggregate Order {
        Entity Order {
            aggregateRoot
			
            - OrderID orderId
            - List<OrderItem> items
            - OrderState orderState
            - @Policies policies
            long userId
            DateTime createTime
            DateTime completeTime

            def calculateSumPrice();
            def postOrderAction();
        }

        enum OrderState {
            aggregateLifecycle
            PAYED,UNPAYED,CANCELED
        }

        ValueObject OrderID {
            int id
        }
       
        ValueObject OrderItem {
            int productId
            float price
        }
        
        DomainEvent OrderSubmitted {}
        DomainEvent OrderRevokedSucc {}
        DomainEvent OrderRevokedFail {}
        DomainEvent OrderPostActionFinished {}
        
    }
}

BoundedContext payContext implements businessDomain {
    type = FEATURE
    domainVisionStatement = "Pay Management"
    implementationTechnology = "Java, SpringBoot"
    knowledgeLevel = CONCRETE

    Aggregate Payment {

        Service PaymentService {
            int doPayment(int orderId) throws PaymentFailedException;
            int rollback(int paymentId) throws paymentRollbackFailedException;
        }

        ValueObject PaymentID {
            int paymentId
        }

        enum PayMethod {
            WEIXIN,ZHIFUBAO,CREDITCARD,SCORE
        }

        DomainEvent PaymentSucceed {}
        DomainEvent PaymentFailed {}
        DomainEvent PaymentRollbacked {}

    }
    
}

UML :

在这里插入图片描述
在这里插入图片描述
​     在实体的构建中,我们应该明确实体的本质特征,挖掘其关键行为,定义其角色和职责,并使其可验证、可跟踪。很多时候,以更为轻量级的不可修改的值对象来代替实体是一个不错的选择。

​     本节以图和CML代码的形式分享了DDD战术设计实践,这中间有太多不够完善的地方。读者可以仔细阅读CML代码来了解具体细节,CML语法可参阅前面所提到的 context mapper 。再次强调示例中只是一个非常粗陋的初版,存在非常多的不足和缺陷,距离一个完整和全面的DDD战术设计还很远。例如如何解决N:N关系,持续集成、接口幂等性等等都没有提及,但这些也是设计过程中必须要考虑的。

​     读者在具体的实现时需要谨慎斟酌,结合DDD设计理念和面向对象分析技术反复迭代才能够取得好的效果,从而实现把核心业务逻辑和业务处理能力沉淀到平台层。

未完,待续…

标签:Domain,DomainEvent,int,Driven,AbstractDomainEvent,ValueObject,Design,extends,def
来源: https://blog.csdn.net/weixin_43171270/article/details/118793177

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有