美文网首页复仇者不联盟
领域驱动设计(一)

领域驱动设计(一)

作者: MaxZing | 来源:发表于2018-02-02 16:45 被阅读36次

    领域驱动设计(Domain Driven Design)一下简称DDD
    DDD是为了创造一个可测试的,可伸缩的,组织良好的软件模型。

    一,采用DDD的原因:

    • 表达准确的业务规则,不单单是包容产品设计(领域专家)和开发者,而是将其组成一个密切合作的团队。
    • 准确的传达业务规则表现在完美实现设计的业务
    • 帮助业务人员提高,DDD中每个人都在学习
    • 知识集中可以将知识分享出去,不是仅被某些人掌握
    • 开发和设计之间不存在翻译,而是使用相同的“语言”沟通
    • 设计就是代码,代码就是设计,编码设计来自多次试验。
    • DDD设计有战略和战术两种方式,战略设计帮助理解哪些投入是必要的,哪些是可以重用的,需要哪些人参与。战术设计帮助创建模型中是各个部件。

    二,DDD主要关注三个方面:

    1. 将开发和产品设计聚集在一起,可以反映出产品是设计思维模型
    2. 关注业务战略,包含战略和战术设计。从而实现面向服务架构和业务驱动架构
    3. 通过建模工具,将领域设计转换成软件,同时设计出的软件可测试,具有良好的伸缩性,允许分布式计算

    未经过DDD,导致出现大量的贫血对象
    贫血对象:在领域中,有些对象几乎没有业务操作,并且Getter 和Setter大部分是为了映射数据库里的领域模型。

    • 主要是些公有的getter和setter方法, 并且几乎没有 业务逻辑,或者甚至完全没有业务逻辑——对象嘛,主要就是用来容纳屈 性值的?
    • 软件组件经常使用的领域对象是否包含了系统主要的业务逻辑,并且多数 情况下你需要调用那些getter和setter? 你可能会将这样的客户代码称为服务层(Service Layer)或者应用层(Application Layer) (4, 14)代码。

    ——摘自《领域驱动设计》

    大段大段的setter方法让人崩溃

    customer.setCustomerFirstName(customerFirstName); 
    customer.setCustomerLastName(customerLastName); 
    customer.setStreetAddressl(streetAddressl);
    customer.setStreetAddress2(streetAddress2);
    customer.setCity(city); 
    customer.setStateOrProvince(stateOrProvince);
    customer.setPostalCode(postalCode); 
    customer.setCountry(country); 
    customer.setHomePhone(homePhone); 
    customer.setMobilePhone(mobilePhone); 
    customer.setPrimaryEmailAddress(primaryEmailAddress); 
    customer.setSecondaryEmailAddress (secondaryEmailAddress); 
    

    如果这时候有一个保存方法

    saveCustomer(customer);
    

    咋一看,是保存客户信息。但是在领域中,你不知道业务是何时使用这个方法的,即无法映射实际的业务场景。

    然后过一段时间,customer的属性发生了变化,添加了一两个属性,并且属性的参数需要符合一定的要求,就会出现下列代码:

    if (customer == null) {
      customer = new Customer(); 
      customer.setCustomerid(customerid);
    }
    if (customerFirstName 1= null) {
      customer.setCustomerFirstName(customerFirstName); 
    }
    if (customerLastName ! = null) { 
      customer.setCustomerLastName(customerLastName); 
    }
    ...
    ...
    ...
    

    这种代码已经表示数据-映射开始变糟了。你已经不清楚什么时候参数是必须的,该不该保存customer。
    而且随着时间的流逝,方法变化的来龙去脉越来越模糊,弄清楚需要花费大量的时间。

    三,DDD 的《通用语言》

    通用语言是用来交流领域中(业务),行业专家和程序编写者沟通交流的语言,既不是行业专家使用的专业术语,也不是专门的业务语言。通用语言主要是方便团队中的行业专家以及开发人员沟通,比如,模型图,领域文档等(包含领域中术语与术语含义的解释,通常有个表格)

    按照通用语言的业务划分,不应该出现贫血对象,那么上述代码在DDD的指导下会变成:

    public interface Customer { 
      void changePersonalName( String firstName, String lastName); 
      void postalAddress(PostalAddress postalAddress); 
      void relocateTo(PostalAddress changedPostalAddress); 
      void changeHomeTelephone(Telephone telephone); 
      void disconnectHomeTelephone(); 
      void changeMobileTelephone(Telephone telephone); 
      void disconnectMobileTelephone (); 
      void primaryEmailAddress(EmailAddress emailAddress); 
      void secondaryEmailAddress(EmailAddress emailAddress); 
    }
    

    这样,业务就会体现在接口中,而方法对应的应用层也会随之变化:

    @Transactional
    public void changeCustomerPersonalName( String customerld, String customerFirstName, String customerLastName) { 
      Customer customer = customerRepository.customerOfId(customerid); 
      if (customer == null) {
        throw new IllegalstateException("Customer does not exist");
      }
      customer.changePersonalName(customerFirstName, customerLastName); 
    }
    

    你会说,这个方法太单一了。没错,在DDD中,参照模型对数据修改,不需要使用一个方法,然后后面跟上一大堆null去判断了。

    通用语言不是万能的,而是在领域中普遍的,表达清楚的;一般会有领域界限上下文限定,如果想映射到其他领域中,大部分情况会失败

    作为开发者,我们都是技术思想者,技术实现对于我们来说并不是什么难事。我并不是说技术地思考不好,只是说有时少从技术层面去思考会更好。这么多年来,我们都习惯了单从技术层面完成软件开发,那么现在,是时候考虑一种新的思考方式了。为你的业务领域开发一门通用语言是一个好的出发点。

    一 一 实现领域驱动设计

    相关文章

      网友评论

        本文标题:领域驱动设计(一)

        本文链接:https://www.haomeiwen.com/subject/wclrgxtx.html