`
uiafzhdl
  • 浏览: 25313 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

从贫血领域模型到丰富领域模型 第二部分

阅读更多

4.重构到丰富领域模型构架<o:p></o:p>

4.1.技术方案<o:p></o:p>

为了简便起见,下文中使用AB这两个别名分别代表“贫血领域模型”和“丰富领域模型”,使用名称空间表示模型中的层,如B::应用层表示丰富领域模型的应用层。

通过前面的比较,可以很容易的得到下面转换的方案:

1)保持表现层不变

2)分离出来应用层。从A::领域层移出应用逻辑形成B::应用层。

3)重构一个纯粹的领域层。将A::领域层的领域逻辑部分进行分解:

    # 将概念性的逻辑重构到B::领域层.实体和B::领域层.值对象;
    # 将操作性逻辑重构到B::领域层.服务;
    # 将数据源访问抽象为存储库接口,存储库的实现由Ioc容器注入。
<!----><!---->

4)重构数据访问对象,使其实现领域层的存储库接口。

5)基础设施层保持不变。

不多做解释,下面通过代码进行说明。

4.2. 示例代码<o:p></o:p>

还是前面的在线购物网站,但这次使用了一个稍微能体现领域逻辑的用例:列出与当前产品相关的其他产品。

1)页面发出请求

下面是一个可能的JSF代码片断:

  1. <h:commandLink action="#{product.related}" value="#{相关产品}">  
  2.     <f:param name="productid" value="#{product.id}" />  
  3. <!---->h:commandLink>  

2)代理到控制器

与前面一样,只是增加了一个响应查询相关产品的响应事件:

package yourpackage.action;<o:p></o:p>

......<o:p></o:p>

public class ProductAction extends BaseAction {<o:p></o:p>

         //通过依赖注入的服务<o:p></o:p>

private ProductService productService;<o:p></o:p>

//作为模型对象的领域对象<o:p></o:p>

private Product product;<o:p></o:p>

private Integer id;<o:p></o:p>

//响应查看产品信息的事件<o:p></o:p>

public String edit() {<o:p></o:p>

        product = productService.getProduct(id);<o:p></o:p>

return “product”;  //JSF将其解析为product.xhtml视图<o:p></o:p>

}<o:p></o:p>

//响应查询相关产品的事件<o:p></o:p>

public String related() {<o:p></o:p>

        product = productService.getRelatedProduct(id);<o:p></o:p>

return “products”;  //JSF将其解析为products.xhtml视图<o:p></o:p>

}<o:p></o:p>

<o:p> </o:p>

}

3)领域层的服务

与前面贫血领域模型的代码中有一些区别:用Reporsitory代替了Dao,并增加了一个获取产品信息的领域逻辑方法。

package yourpackage.service;

......

public class ProductServiceImpl extends BaseService implements ProductService {

    //通过依赖注入的存储库实现

private ProductRepository productRepository;

<o:p> </o:p>

//获取产品信息的领域逻辑方法

public Product getProduct(Integer id) {

        return productRepository.getProduct(id);

}

//获取产品信息的领域逻辑方法

public Product getRelatedProduct(Integer id) {

        Product product= productRepository.getProduct(id);

return product.getRelated();

    }

}

4)领域层的实体

一切魔法都发生在这里!

现在我们的实体除了封装数据外,还有了一个真正的领域方法:getRelated()

package yourpackage.model;

<o:p> </o:p>

import org.springframework.beans.factory.annotation.Configurable;

import org.springframework.beans.factory.annotation.Autowire;

......

<o:p> </o:p>

@Entity

@Configurable(autowire=Autowire.BY_TYPE ,dependencyCheck=true)

public class Product {

<o:p> </o:p>

//通过依赖注入的存储库实现

private ProductRepository repository;   

public void setProductRepository(ProductRepository repository) {

    this.repository = repository;

}

<o:p> </o:p>

       @Id @GeneratedValue(strategy=GenerationType.AUTO)

       @Column(name="Id")

       public Long getId() {

              return id;

       }

<o:p> </o:p>

       @Column(name="Name", length=30, nullable=false)

       public String getName() {

              return name;

       }

<o:p> </o:p>

    //这是一个领域逻辑方法

public List <product> getRelated() {</product>

    return repository.getRelated(getId());

}

}

下面来解释一下魔法的背后到底发生了什么。

Spring 2.0开始,在AspectJ的帮助下,提供了一个annotation驱动的方面用于任何对象的依赖注入,即使这些对象并不是由容器所创建。最典型的就是由Hibernate管理的领域对象。

@ Configurable是一个标记性的Annotation,告诉Spring,在实例化这个类的时候需要使用一个原型。autowire=Autowire.BY_TYPE则告诉Spring,这个原型是根据类型自动创建的(autowiring),这避免了在Spring配置文件中显式的定义一个Product类型的Bean。另外还需要通过dependencyCheck=true来告诉Spring,在新建Product类型的实例时进行依赖检查。由于我们的Product中出现了setProductRepository(),而Spring恰好发现了一个名为productRespositoryBean

 
  1. <bean id="productRepository" class="yourpackage.dao.ProductRepositoryImpl" />  

于是就将这个Bean的实例设置到Product对象的repository。这就是大家早已熟悉的依赖注入,只不过这一次发生在了领域对象的身上。

这一切之所以能够发生,是因为背后一个叫做AnnotationBeanConfigurerAspect的方面在起作用。使用该类需要引入Spring发行包中的spring-aspects.jar,并且在配置文件中进行如下定义:

  1. <aop:spring-configured/>  

最后要做的一件事是,必须有某种机制使得被注解的类能够被AspectJ weaver织入。一种方法是用AspectJajc编译器对代码进行预编译,另外一种方式是使用AspectJ Load-time weaving (LTW)

如果在Java 5环境使用LTW,需要在类路径下的META-INF目录中编写一个名为aop.xml的文件,以告诉AspectJ对那些类进行织入处理:

aop.xml 代码
 
  1.   "-//AspectJ//DTD//EN"    "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">      
  2.   
  3. <aspectj>  
  4.   <weaver>   
  5.     <include within="yourpackage.domain.Product"/>  
  6.   <!---->weaver>  
  7. <!---->aspectj>  

然后,需要在JVM加载参数中指定下面的内容:

-javaagent: <path-to-ajlibs>/aspectjweaver.jar</path-to-ajlibs>

现在可以说大功告成了。

5DAO对象

现在DAO需要实现的接口变成了领域层的ProductRepository

package yourpackage.dao;

<o:p> </o:p>

import yourpackage.domain;

......

public class ProductDaoJpa extends BaseDaoJpa implements ProductRepository {

       public Product getProduct(Integer id) {

              return (Product) getJpaTemplate().find(Product.class, id);;

       }

<o:p> </o:p>

       public Product getRelatedProduct(Integer id) {

              //这里是具体的实现代码

       }

}

5.结论<o:p></o:p>

要构建一个纯粹的领域模型,往往需要在领域对象中直接使用外部服务,如数据库访问,外部资源,或其他必要的服务。在没有强大的AnnotationAOPDI技术的支持下,这些外部服务或资源很难被注入到领域对象中,由此形成了贫血模型的设计风格。

特别地,对于Spring用户来说,在2.0版发布之后,问题的解决变得更容易一些。利用Spring集成的AspectJ实现向领域对象进行依赖注入,可以使领域对象可以表达更丰富的逻辑,从而过渡到丰富领域模型。在这个关键问题解决之后,剩下的问题也就迎刃而解了。
分享到:
评论
5 楼 ray_linn 2008-10-31  
其次 AOP的引入会不会带来测试上麻烦~~~
4 楼 ray_linn 2008-10-31  
ASPECTJ有两大缺点:

1. 静态织入ajc十分不稳定,平均每编译5次就有出现内存不足或者其他莫名奇妙的错误。
2. AspectJ Load-time weaving,对不少项目来说不具备意义,尤其是对需要发布项目到公用主机上的项目,添加一行参数可能被对方所拒绝。
3 楼 ray_linn 2008-10-30  
ASPJECTJ的注入简直是...一堆破旧的陈货。在Eclipse上一但enabled了这个,就意味着你的系统将不停的死机和耗费内存。


ASPJECTJ的注入远不入.net里的扩展方法来得漂亮,把贫血模型的operation attached到domain上,就成了。
2 楼 uiafzhdl 2006-12-22  
引用
江南白衣     2 小时前

非常好~~

致谢了。
刚看到一篇不错的blog,里面对容器外的依赖注入方式有更全面的讨论,分享一下:
http://igorstoyanov.blogspot.com/2005/12/dependency-injection-or-service.html
1 楼 江南白衣 2006-12-22  
非常好~~

相关推荐

    大白话领域驱动设计DDD视频教程

    第2章 领域分析模型 核心域,支撑子域,通用子域 微服务和DDD是什么关系? 传统模式下如何合理的划分各种域 基于DDD的方式进行域划分 什么是通用语言 什么是限界上下文? 限界上下文和子域的关系 基于电商系统按流程...

    DDD领域驱动设计day01.pdf

    - 第二天关注DDD实践篇,讲解如何基于领域模型进行数据库和程序设计,以及如何设计聚合、工厂和仓库。 - 第三天聚焦DDD架构篇,讨论如何构建支持领域驱动设计的技术中台和微服务架构,以及通过整洁架构支持技术架构...

    常染色体隐性病模型.pptx

    例如,某地区有 10% 的黑人是镰状网性贫血症隐性患者,如果当地政府采取控制结合措施,到下一代的隐性患者将减少到 5% ;而且只要进行四代的控制,隐性患者所占百分比不到 1% 。 思考: (1)基因分布表给出的概率...

    JavaEye论坛热点月报 总第7期

    【JavaEye论坛热点月报 总第7期】 在这一期的JavaEye论坛...这些热点话题反映了当时JavaEye论坛上最活跃的技术讨论,涵盖从基础框架到高级工具,再到具体应用实践的广泛领域,为开发者提供了丰富的学习和交流资源。

    2016春八年级科学下册第2章微粒的模型与符号测试题3浙教版.doc

    这篇文档是针对初中科学课程,特别是八年级下册第二章“微粒的模型与符号”的测试题,旨在考察学生对化学基础知识的理解,包括化学式、元素符号、分子结构以及原子间的关系。以下是对题目中涉及知识点的详细解释: ...

    PyTorch-YOLOv3-master.rar

    6. 应用部署:将训练好的模型集成到实际应用中,如医疗诊断系统,实现自动化血细胞检测。 标签“计算机视觉 yolov3”强调了这个项目属于计算机视觉领域,使用了YOLOv3技术。计算机视觉是AI的一个分支,专注于让机器...

    数模_化验结果判别与matlab程序.doc

    最后,对比第二问和第四问的结果,进行深入分析。 在建模过程中,假设了数据的准确性,其他微量元素的影响较小,且外界条件对肾炎的影响可忽略。模型建立涉及到了患者和正常人的离差矩阵、协方差矩阵,以及马氏距离...

    spring jpa reference

    传统的领域类(domain classes)往往是贫血模型,缺乏面向对象或领域驱动的设计。引入Spring和JPA的结合使用,可以极大地简化这一过程,让开发者更专注于富有领域模型特性的持久层的实现。 Spring Data JPA的仓库...

    2018年八年级科学下册期末复习第2章第四节组成物质的元素及其符号练习题新版浙教版

    6. 元素符号书写:正确的元素符号如硫(S),第一个字母大写,第二个字母小写。 7. 元素符号一致性:符号书写正确且与名称相一致的是硫(S)。 8. 元素符号首字母:氯、碳、钙、铜的首字母都是"C",属于同一组。 ...

    Java使用技巧(TXT文档)

    4. **设计模式**:在"实体对象的抽象以及一种基于数据库的实现(转).txt"中可能涉及到贫血模型和富模型两种常见的对象关系映射设计模式。贫血模型的对象只包含数据,而业务逻辑存在于服务层;富模型则让对象包含数据...

    贵州省遵义市高坪中学2015_2016学年九年级化学上学期第二次月考试题含解析新人教版

    5. **化学反应微观示意图**:题目展示了反应的微观模型,涉及到了化合反应,分子和原子的种类在反应前后保持不变,以及分子数量的变化。 6. **化学用语**:正确理解化学符号是关键,例如2MnO42﹣表示两个锰酸根离子...

    文字稿(更新到第三十课时)1

    18. **贫血模型与充血模型**:对比两种不同设计模式的优缺点,探讨最佳实践。 19. **课程总结**:回顾整个课程,强调掌握QFramework System Design Architecture对架构设计的重要性。 课程通过实例教学,逐步揭示...

    s2sh网上购物项目

    在设计上,可能采用贫血模型或充血模型,根据业务需求选择合适的对象状态管理方式。 数据库设计是项目的关键部分,可能包括用户表、商品表、订单表、购物车表等,需要考虑到数据的一致性、安全性和性能。例如,用户...

    10Hibernate 程序设计

    - **POJO对象**:与数据库表对应的Java类,通常遵循贫血模型,只包含数据属性。 - **映射文件**:定义了类与表的映射关系,包括字段映射、主键生成策略等。 - **应用程序**:通过Hibernate API与数据库交互,如`...

    Expert One-on-One J2EE Design

    2. **设计原则**:强调了面向服务架构(SOA)和分层架构的重要性,讨论了如何根据业务需求选择合适的设计模式,例如贫血模型和富模型,以及何时使用无状态会话Bean和有状态会话Bean。 3. **性能优化**:探讨了J2EE...

    内蒙古自治区乌兰察布市凉城县2020-2021学年高二下学期期末考试生物试题.doc

    5. 免疫防御:中性粒细胞吞噬是第二道防线;血浆蛋白破坏病原体非第一道防线;皮肤阻挡细菌属于第一道防线;对外来器官的排异反应是免疫系统的第三道防线。 6. 神经元间传递:兴奋可通过突触传递;④神经递质释放是...

    java项目之物流配货网源码.zip

    - **贫血/富模型**:根据业务场景选择合适的模型设计,提升数据访问的灵活性和安全性。 5. **测试与调试** - **单元测试**:使用JUnit等工具对单个功能模块进行测试。 - **集成测试**:检查不同模块间的协作是否...

    浙江省平阳县第二中学2015_2016学年高二生物上学期期中试题鸭

    2. 糖类的比较:淀粉、纤维素和糖原都是多糖,由葡萄糖单体组成,但结构差异导致它们的功能不同。它们的共同点在于基本组成单位都是葡萄糖(六碳糖),而非六碳糖;不含有氮元素(N);并非所有都是细胞内储存能量的...

Global site tag (gtag.js) - Google Analytics