`
taowen
  • 浏览: 193501 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

贫血的Domain Model

阅读更多
好老的话题啦。拿出来炒炒冷饭。各位见谅。
——————————————————————
Domain Model贫血是说属于Domain Model的逻辑没有放在Domain Model中。那是哪些逻辑没有放到Domain Model中,从而导致贫血一说呢?原因有很多,但是我认为最主要是Service中的那些逻辑。而这些逻辑又有一个共同的特点就是依赖于DAO,或者说需要查询数据库。Robbin的帖子:http://www.iteye.com/topic/57075,举了一个很好的例子。我取其中的一个部分在这里做演示用。

public class Employee {
    private Set<Task> tasks = new HashSet<Task>();
}


public class Task {
    private String name;
    private Employee owner;
    private Date startTime;
    private Date endTime;
}


这是一个很简单的一对多的关系。现在要查找指定员工的处理中的任务。如果忽略数据库的存在,我想大部分的同志都会这么实现:

public class Employee {
    private Set<Task> tasks = new HashSet<Task>();
    public Set<Task> getProcessingTask() {
       ...
    }
}


这也符合OO数据隐藏的基本原则。但是如果有数据库存在,怎么写就不那么容易决定了。如果没有Hibernate这样的ORM。那肯定是:

public class TaskDAO {
   public Set<Task> getProcessingTasks(Employee employee) {
      ...//sql
   }
}


那我觉得,这就导致了Domain Model的失血。因为没有数据库的时候,这这个方法本来应该在Employee上的,而不是在DAO上的。
如果有Hibernate呢?是不是我就可以把这段代码写到Employee里面去呢?

@Entity
public class Employee {
    @OneToMany
    private Set<Task> tasks = new HashSet<Task>();
    public Set<Task> getProcessingTask() {
       ...
    }
}


还是有问题。因为访问tasks的时候,Hibernate会去加载数据。getProcessingTask会便利所有的task。如果task的数量很多,这降极大的影响性能。所以为了能够享受到关系数据库查询速度的好处,我们要还要利用SQL。于是DAO又再次地找到了自己的位置。那么怎么解决这个问题呢?在http://www.iteye.com/topic/57075的回帖中nihongye同学提出了一个解决方案。本质来说就是不让hibernate来映射tasks,改由查询来获得。加上Spring支持的@Configurable标记,我们可以把代码写成这样

@Entity
@Configurable
public class Employee {
    private TaskDao dao;
    public Set<Task> getProcessingTask() {
        return dao.getProcessingTask(this);
    }
    public void setTaskDao(TaskDao dao) {
        this.dao = dao;
    }
}


我们当然还可以把TaskDao替换成变的形式。比如http://www.iteye.com/topic/65406里firebody提到的那样。但是本质上来说,都是让Employee能够直接去使用Hibernate做查询。但是坏处是给Domain纯净分子的口实。虽然,我认为和ActiveRecord类似,entity绑定在数据库上没啥不好。另外一个缺点就是,要么仍然有一个Dao来封装查询逻辑的实现,要么Employee的实现中出现太多的hibernate api,而且写法复杂。这也就是Robbin一再强调,ActiveRecord那样的api在Java世界中不是不可以,而是实现复杂难度高的原因。注入可以解决问题,但是对Hibernate的依赖强而且写法丑陋。
那么有没有更优美的方案呢?有:

public class Employee {
    private RichSet<Task> tasks = new DefaultRichSet<Task>();
    public RichSet<Task> getProcessingTasks() {
        return tasks.find("startTime").le(new Date()).find("endTime").isNull();
    }
...
}



RichSet是我自己编造的一个名字。它是一个”rich“的set。其实就是附加了一些find,sort,sum之类的操作。

public interface RichSet<T> extends Set<T> {
    Finder<RichSet<T>> find(String expression);
    int sum(String expression);
}


DefaultRichSet是这些附加操作的内存版本的实现。这个能解决问题么?还是不能,这时候getProcessingTasks的时候,richSet还是去遍历内部的_tasks,然后把结果过滤出来。而且,hibernate还拒绝接受这样set。为了让hibernate能够接受RichSet,我们需要这么写配置文件。

<hibernate-mapping default-access="field" package="net.sf.ferrum.example.domain">
    <class name="Employee">
        <tuplizer entity-mode="pojo" class="net.sf.ferrum.RichEntityTuplizer"/>
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="salary"/>
        <many-to-one name="department"/>
        <set name="tasks" cascade="all" inverse="true" lazy="true">
            <key/>
            <one-to-many class="Task" />
        </set>
    </class>
</hibernate-mapping>


通过指定RichEntityTuplizer,我们可以控制Hibernate的动态增强过程。

public class RichEntityTuplizer extends PojoEntityTuplizer {
    public RichEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
        super(entityMetamodel, mappedEntity);
    }

    protected Setter buildPropertySetter(final Property mappedProperty, PersistentClass mappedEntity) {
        final Setter setter = super.buildPropertySetter(mappedProperty, mappedEntity);
        if (!(mappedProperty.getValue() instanceof org.hibernate.mapping.Set)) {
            return setter;
        }
        return new Setter() {
            public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException {
                Object wrappedValue = value;
                if (value instanceof Set) {
                    HibernateRepository repository = new HibernateRepository();
                    repository.setSessionFactory(factory);
                    wrappedValue = new HibernateRichSet((Set) value, repository, getCriteria(mappedProperty, target));
                }
                setter.set(target, wrappedValue, factory);
            }

            public String getMethodName() {
                return setter.getMethodName();
            }

            public Method getMethod() {
                return setter.getMethod();
            }
        };
    }
}


这样,tasks就不再是DefaultRichSet了。Hibernate会尝试去增强为PersisentSet,但是被RichEntityTuplizer改写为增强HibernateRichSet了。这样就形成了HibernateRichSet -> PersisentSet -> DefaultRichSet -> HashSet 的包含关系。

当用户尝试在tasks上做find的时候,就不再是DefaultRichSet来做collection遍历了,而是HibernateRichSet去拼装一个DetachedCriteria。最后当用户在查询的结果上取size()或者取具体元素的时候,这个criteria被拿去求值。

通过使用RichSet,domain model具有了对自身进行查询的能力。更重要的是,这种能力的获得,不是通过把Hibernate session注入到domain model中。domain仍然是纯净的,没有依赖于数据库的东西。而且domain是可以脱离容器使用的。new Employee出来就可以直接使用,测试。区别只是经过repository增强的entity会使用sql,而transient的entity所有的查询都是通过遍历实现的。

没有了DAO之后,Domain Model是不是能够摆脱贫血的困扰呢?这个还需要观察。不过我认为至少是向前迈了一步了。
  • ferrum.zip (90.6 KB)
  • 描述: 新版代码,废除了手工的增强,改由Tuplizer来搭Hibernate的顺风车。
  • 下载次数: 302
分享到:
评论
57 楼 nihongye 2008-05-12  
robbin 写道
IOC

这个IOC怎么理解?其实程序new Person(Session session,DAO dao)就是反转控制吖,注入的工作可以让容器做,也可以调用者来做,对于被调用者,享有同样清静。当然回到实际的应用,没有容器来注入,会很惨。在这种情况下,感觉声明性的注入加谁创建谁负责调用容器注入,挺好的解决方案。
56 楼 jjx 2008-05-12  
可以用service locator,从ioc中获取hibernateTemplate或类似的东西
public static IList findAll(){
    return getHibernateTemplate().Find("from Employee e").....
}
 
static HibernateTemplate getHibernateTemplate(){
return (HibernateTemplate)ContextRegistry.GetContext()["hiberanteTemplate"];
}


不一定一定要以注入的方式

55 楼 taowen 2008-05-12  
getAllEmployee怎么实现啊?如果是用hibernate的话,至少要引用session吧。session从哪里获得呢?
另外谁来使用getAllEmployee呢,能不能选定一个特定的场景。比如选定Web框架,选定要完成的功能。不是很能领会静态引用getAllEmployee的好处。
54 楼 robbin 2008-05-12  
taowen 写道
Robbin能否举一个例子如何像ActiveRecord那样用静态方法调用领域逻辑。



public class Employee {  
     @OneToMany  
     private Set<Task> tasks = new HashSet<Task>();  
     public Set<Task> getProcessingTask() {  
        ......
     }  
     public static getAllEmployee() {
        ......
     }
} 


比方说类似这样的,如果不依赖特定对象实例的方法,直接用静态方法如何?如果getProcessingTask用到其他对象的方法,如果是依赖对象状态,可能就是方法参数传递进去,如果不依赖,直接调用该对象静态方法。

不知道这样去用,会不会有什么问题。自从IoC兴起以后,貌似就没有人这样去用了,大家都极力避免静态方法的出现。


53 楼 taowen 2008-05-12  
Robbin能否举一个例子如何像ActiveRecord那样用静态方法调用领域逻辑。
52 楼 robbin 2008-05-12  
taowen 写道
抛弃Service层太难了。这个正如你所说,是Ruby和Java的WEB执行环境的差异造成的。连接的开关还好说,事务要加在Domain对象可真是不容易。不过不知道我的方案部分剞劂了贫血的问题不?是不是大家又开始觉得Domain对象缺的血是事务控制了?
但是我不大认同不能抛弃service层,实现Rich Domain Model就没有意义的说法。但是我也无法给出实际的例子来证明,在保持Service层情况下,实现Rich Domain Model的好处。我正在思考一个更具有实际背景的例子,来比较一下各种实现方式的差别。
另外你提及的Web层的Developer。是不是隐含的说,写web层的开发者不是写service层的开发者?至少在我们公司,是不存在这个区别的。如果都是一个人来写的话,把事务控制放在service层中,还是在web层中手写,那纯粹就是实现优劣的问题了,不牵涉团队协作问题。


便是自己一个人写代码,这代码写的多了以后,几十个domain以后,自己也会时不时出现困扰,需要查阅源代码才能确定。

事务控制不妨粗糙一点,数据库连接可以最后再关闭,所以在Web环境可以使用OpenSessionInVew,在测试环境可以tearDown去解决。那么唯一的问题是:能否抛弃IoC,就像ActiveRecord那样,用静态方法调用写领域逻辑得了。这貌似也没有什么大问题,除了单元测试可能麻烦点。
51 楼 taowen 2008-05-12  
抛弃Service层太难了。这个正如你所说,是Ruby和Java的WEB执行环境的差异造成的。连接的开关还好说,事务要加在Domain对象可真是不容易。不过不知道我的方案部分剞劂了贫血的问题不?是不是大家又开始觉得Domain对象缺的血是事务控制了?
但是我不大认同不能抛弃service层,实现Rich Domain Model就没有意义的说法。但是我也无法给出实际的例子来证明,在保持Service层情况下,实现Rich Domain Model的好处。我正在思考一个更具有实际背景的例子,来比较一下各种实现方式的差别。
另外你提及的Web层的Developer。是不是隐含的说,写web层的开发者不是写service层的开发者?至少在我们公司,是不存在这个区别的。如果都是一个人来写的话,把事务控制放在service层中,还是在web层中手写,那纯粹就是实现优劣的问题了,不牵涉团队协作问题。
50 楼 robbin 2008-05-12  
taowen 写道
To Robbin:
连接的获取和释放,和事务的管理是Service层的职责,无论Domain Model是贫血还是不贫血,都不会牵涉到连接和事务的管理。Service在使用Domain Model的时候,就要保证连接已经获得。事务可以用在Service层的方法上加Annotation,用AOP来织入实现的代码。
对于连接和事务的存在,使得在Java中必须存在Service层。这个是架构原因造成的,和Rich Domain Model无关。当然,由于Service层的存在,Java写的程序自然无法如RoR那么简洁了。所以我认同你的这个观点。确实,很多时候,Service层的代码写起来很无聊。但是为了管理事务和安全,又不得不有这么一层。

在我的方案中,Domain对象的注入不是由IoC容器来完成的。Domain对象的注入,其实是POJO->PO的过程。这个过程是由Hibernate完成的。Java的class虽然不是open的,但是也非完全closed。Hibernate用反射同样实现了Collection的增强。通过改写Hibernate增强POJO的过程,让Domain对象具有了查询自身Collection的能力。我认为具有了查询能力,Domain Model可以更加Rich。更重要的是,人们所担心的Domain对象变得复杂无比,与持久化代码发生纠缠的局面并没有出现。因为实现细节被RichSet,RichList这样的Collection API隔离了。甚至RoR更好,因为Domain对象可以脱离数据库构造出来做单元测试,完全不牵涉容器和数据库。


我原意是指抛弃Service层,不过下载你的代码看了单元测试以后,明白了。其实我希望看到的是消除Service层,否则Rich Domain Model的意义就被削弱很多了。因为最终你不得不在Service层针对domain logic再封装一层transaction script,这样Service层就显得颇为罗嗦。

而且更麻烦的是,会造成Web层的程序员的困扰。他明明看到domain model的逻辑是自洽的,却偏偏要搞清楚哪些logic不能直接调用,必须通过Service;哪些logic可以直接调用,不能通过Service,否则就会出错。与其这样,倒不如干脆把所有的逻辑剥离到Service层更直观了。

所以我的想法就是:如果不能够消除Service层的话,使用rich domain model没什么意义。



49 楼 taowen 2008-05-12  
Ashela 写道
Configurable这个annotation需要多出很多aspectj的配置,运行起来也有点麻烦,是java目前在rich domain model这个问题上的权宜之计,不过如果真正实现起来对于前期的分析是很有好处的,只不过编码的时候有些麻烦

其实我没有实践过这个option。希望有经验的人贡献一些实际的例子。不过我相信,增强Collection比注入DAO要更好(因为不依赖容器和数据库)。
48 楼 taowen 2008-05-12  
To Robbin:
连接的获取和释放,和事务的管理是Service层的职责,无论Domain Model是贫血还是不贫血,都不会牵涉到连接和事务的管理。Service在使用Domain Model的时候,就要保证连接已经获得。事务可以用在Service层的方法上加Annotation,用AOP来织入实现的代码。
对于连接和事务的存在,使得在Java中必须存在Service层。这个是架构原因造成的,和Rich Domain Model无关。当然,由于Service层的存在,Java写的程序自然无法如RoR那么简洁了。所以我认同你的这个观点。确实,很多时候,Service层的代码写起来很无聊。但是为了管理事务和安全,又不得不有这么一层。

在我的方案中,Domain对象的注入不是由IoC容器来完成的。Domain对象的注入,其实是POJO->PO的过程。这个过程是由Hibernate完成的。Java的class虽然不是open的,但是也非完全closed。Hibernate用反射同样实现了Collection的增强。通过改写Hibernate增强POJO的过程,让Domain对象具有了查询自身Collection的能力。我认为具有了查询能力,Domain Model可以更加Rich。更重要的是,人们所担心的Domain对象变得复杂无比,与持久化代码发生纠缠的局面并没有出现。因为实现细节被RichSet,RichList这样的Collection API隔离了。甚至RoR更好,因为Domain对象可以脱离数据库构造出来做单元测试,完全不牵涉容器和数据库。
47 楼 Ashela 2008-05-12  
Configurable这个annotation需要多出很多aspectj的配置,运行起来也有点麻烦,是java目前在rich domain model这个问题上的权宜之计,不过如果真正实现起来对于前期的分析是很有好处的,只不过编码的时候有些麻烦
46 楼 robbin 2008-05-12  
我是不太赞同Java采用Rich Domain Model的,起码Java的框架做不到Rails的ActiveRecord那样简洁,这不仅仅是语法差异造成的,也和Rails的部署运行方式有紧密的关系。

1、Rails的进程运行模式是每个进程持有一个永久连接,一直不释放。

由于Rails不需要释放连接,所以不存在数据库连接资源的清理问题。但是Java的每个线程最终要释放数据库连接,所以必须精心的设计和编码,确保资源得到正确顺序的释放。但是一旦考虑到一个数据库连接的范围内,要跨多个domain model的方法调用进行数据库访问,那么你如何确定连接释放的顺序和时间点?起码你不可能在domain model的方法调用内部进行close了,必须依赖外部的容器管理,比方说依赖Spring提供的资源管理能力,由Spring来确认最后一个方法调用结束之后来帮助你关闭数据库连接。正因为Java的domain model摆脱不掉外在容器的依赖,所以他没有办法做到ActiveRecord那么简洁。

2、Rails的事务管理机制是很粗糙的,不像Java的事务管理那么精细

Rails默认情况下是单步提交的数据库事务,如果你希望跨多个model的事务,则必须手工写代码来管理。当然用Java也可以手工管理,但是对于已经适应了由容器来提供声明式事务管理的程序员来说,能够接受在Web层手工写丑陋的Transaction代码来管理事务的方式吗?

3、Rails没有IoC,但是有open class和mixin

因为ruby的open class和mixin,所以Rails没有IoC并不是什么问题,domain之间的调用不需要依赖外部容器,单元测试也不需要依赖外部容器,但是Java没有open class和mixin,所以必须强调接口编程和IoC容器管理,但这样一来,事情就复杂了,你背着一个容器编程,必须受到容器的制约。

因为以上的三个原因,Java要实现类似ActiveRecord的rich domain model,就面临比Ruby困难的多的问题,处处要背着一个IoC框架,而且这还意味着你的domain model也应该由IoC框架来创建,否则IoC框架无法给你注入依赖关系。所以这个IoC具有很强的传染性,你必须把所有的依赖关系全部放在IoC的控制之下。但是偏偏你用IoC去管理domain model,特别是prototype的model却是一件非常复杂和困难的事情,尤其Spring框架更是如此。

因此我个人不看好Java的rich domain model,尤其是当你不能摆脱Spring/Hibernate依赖的情况下,无法真正实现rich domain。所以我更希望看到Java领域出现一些新的框架或者思路出来,不要老是Spring/Hibernate那一套。或者可以这样说,正是Spring/Hibernate导致了Java领域贫血模型的出现,如果没有超越Spring/Hibernate(EJB3/JPA也一样)的Java框架出现,是不可能rich domain的。
45 楼 pig345 2008-05-11  
taowen 写道
JPQL和HQL就不是持久化逻辑。他们是查询逻辑。查询逻辑是典型的Domain Model应该关心的东西。

呵呵,也是。
那就更需要在Domain中使用JPA了。
44 楼 taowen 2008-05-11  
JPQL和HQL就不是持久化逻辑。他们是查询逻辑。查询逻辑是典型的Domain Model应该关心的东西。
43 楼 pig345 2008-05-11  
taowen 写道
同意你的说法。使用内存数据库,然后再用spring给domain对象注入一个generic的DAO。我上文提到的解决方案,其实那个RichSet就是一个generic DAO。而注入是通过hibernate实现的。异曲同工而已。也同意你对于脱离数据库“可测试性”的质疑。我也没有明确的例证可以说明其优点。不过,通过RichSet的隔离,至少使用数据库和不使用数据库的选择,交在了你的手上,而不是被框架给限定住了。另外RoR的Fixture让数据库相关的测试变得容易。但是Java中缺乏相因的设施,使得结合数据库的测试显得相对冗长。
其实Persistent就不是一层。。。持久化也压根不是逻辑。它只是Domain的一种存在形式。Domain可以在内存中也可以在数据库中,也可以部分在内存中部分在数据库中。

其实我是建议直接使用JPA,毕竟已经是java的标准设施。
另外理论上Persistent应该是透明(无业务逻辑),但目前技术情况下,其实很多的JPQL/HQL里面确实包含了不少的Domain逻辑的判定,Domain使用JPA也能尽量将这些逻辑收集到DomainModel的内部。
42 楼 taowen 2008-05-11  
同意你的说法。使用内存数据库,然后再用spring给domain对象注入一个generic的DAO。我上文提到的解决方案,其实那个RichSet就是一个generic DAO。而注入是通过hibernate实现的。异曲同工而已。也同意你对于脱离数据库“可测试性”的质疑。我也没有明确的例证可以说明其优点。不过,通过RichSet的隔离,至少使用数据库和不使用数据库的选择,交在了你的手上,而不是被框架给限定住了。另外RoR的Fixture让数据库相关的测试变得容易。但是Java中缺乏相因的设施,使得结合数据库的测试显得相对冗长。
其实Persistent就不是一层。。。持久化也压根不是逻辑。它只是Domain的一种存在形式。Domain可以在内存中也可以在数据库中,也可以部分在内存中部分在数据库中。
41 楼 pig345 2008-05-11  
taowen 写道
pig345 写道
DomainObject为什么不能直接用JPA呢,就像使用java.util一样?
再再次提起老帖子
《RichDomainObject的架构设计中,是否可以抛弃DAO?》
http://pig345.iteye.com/blog/79822

给domain对象注入session或者dao最常见的两个反面回答是:形成循环依赖。Domain对象无法脱离数据库存在。但是我并不完全认同这些说法。个人认为Ruby的ActiveRecord其实就是这么干的,而且用得还挺好。但是经过我做过这个实验,我相信,不用DAO,也可以活得挺好,甚至用起来比DAO还方便。


相信尝试过DomainModel的,都会有同感:
在当前的技术条件下,大多数Domain逻辑的实现 本身就是依赖持久化数据的,人为地硬说Domain不依赖持久层,就如同掩耳盗铃--自欺欺人而已,看看Rails里面(相对来说)漂亮干净的ActiveRecord就知道了,它根本就是基于数据库的。
另外,硬将DataAccess从Domain中分离出去,从而说Domain不依赖DAO,其实就是在开玩笑,这必将造成大部分领域逻辑泄露到DAO中或上窜到Service/Facade中,形成“贫血模型+事务脚本”。

从上边的观点看,根本无须顾虑程序代码上Domain层对Persistent层的依赖;
另外,
1)从实际出发,一个完整的企业应用,基本上都需要数据库参与;
2)再考虑到:有效的测试应该是尽量与实际运行环境相符的测试,也就是有数据库参与的测试;
因此,要Domain对象脱离数据库可供测试,基本上就是一个“空想”的优点!

如果只是为了解决测试方便性的问题,前面早有答案:使用内存数据库。
这比使用(花费不少时间自己编写的各种)MockDAO进行测试,要让人踏实多了,毕竟单元测试的环境跟实际运行环境更贴近了一步。

40 楼 taowen 2008-05-11  
这个库的名字都已经取好啦,叫Ferrum,铁元素。这里贴的代码其实就是Ferrum的example。我现在在写一个以CRM的Domain的大一点的例子。在写具体的例子的过程,发现都有哪些需求,从而实现一个框架。当然最终目标是大家拿过去就能用啦。
39 楼 dreamhead 2008-05-11  
陶公子的探索精神值得鼓励,作为一个程序员,我们总应该想办法把事情做到合理,所谓的水平,就是在不断探索过程中提高的。不过,
* 多人协作的项目里面,不管用怎样的方法,保持一致是最重要的。
* 指望所有人都这么编写代码是不现实的,应该让人在大多数情况下只做简单的事。

大家可以想一下,为什么大家普遍比较认可RoR中ActiveRecord的做法呢?

一个重要的原因是ActiveRecord::Base这个类替我们封装好了几乎一切。所以,在我们的Domain Model里面(至少是在那个文件里面),几乎只有我们自己的领域逻辑。就是这样的一个间接层的存在,极大限度的分离了数据库逻辑和领域逻辑。

从这个角度来说,陶公子可以继续自己的探索,将自己探索的这部分进一步封装,比如封装成一个库,让其他人可以简单的应用。
38 楼 taowen 2008-05-10  
大家说的都有道理。Domain Model引入的代价是相当高的。如果系统本身业务逻辑比较少,但是体力活很多。用其他的系统架构或许成本更低,也更好维护。对于Domain Model是不是有必要,就不要在这里讨论了吧。

相关推荐

    对贫血和充血模型的理解

    贫血模型(Anemic Domain Model)源自于传统的MVC(Model-View-Controller)架构,其中模型部分通常是数据容器,包含了属性但很少有或没有业务逻辑。业务逻辑通常被分离到服务层或者控制器中,这样做的好处是使得...

    贫血

    为了解决贫血模型的问题,开发者可能会转向富模型(Rich Domain Model)或领域驱动设计(Domain-Driven Design, DDD)。在DDD中,业务规则和逻辑被封装到领域对象(Domain Objects)中,这些对象不仅包含数据,还...

    领域模型说明及范例代码.zip

    领域模型(Domain Model)和贫血模型(Anemic Domain Model)是两种常见的模型设计模式,它们各有特点,适用于不同的场景。本资料包旨在通过实例对比,帮助初学者理解这两种模型的区别和概念,并提供实际的Java代码...

    领域模型设计技术实战篇.docx

    - 采用领域驱动设计的实践,比如贫血模型(Anemic Domain Model)和富领域模型(Rich Domain Model),以及Repository模式来管理领域对象。 通过上述分析,我们可以看到领域模型设计的关键在于理解业务逻辑,将其...

    JAVA面试题(下).pdf

    16. 领域模型(Domain Model)和贫血模型(Anaemic Domain Model)与充血模型(Rich Domain Model)的区别在于,贫血模型将业务逻辑放在服务层,而充血模型则将业务逻辑放在领域模型的实体中。 17. 测试驱动开发...

    基于struts2 spring2.5 hibernate3的人事管理系统 源码完整包

    这个系统利用了贫血模型(Anemic Domain Model)来实现DAO层,旨在提供高效、稳定且易于维护的企业级解决方案。 首先,Struts2是一个强大的MVC(Model-View-Controller)框架,它负责处理HTTP请求,并将这些请求...

    强悍的自动生成java代码工具.rar

    例如,开发者可以决定是否生成贫血模型(Anemic Domain Model)或富模型(Rich Domain Model),是否使用MyBatis或Hibernate作为持久层框架,以及选择RESTful风格的Controller还是传统的Action风格。 此外,自动...

    多表联合分页查询(Mybatis注解).zip_9AB_mybatis_skillwoc_全注解_多表关联分页查询

    例如,使用贫血模型(Anemic Domain Model)或富领域模型(Rich Domain Model),根据项目需求选择合适的数据访问模式,以及合理地组织Mapper接口和实体类,使代码结构清晰。 总的来说,这个案例涉及了Mybatis注解...

    HCPC管理系统EJB源码

    - EJB2.0的设计通常遵循一些模式,如贫血模型(Anemic Domain Model)和富模型(Rich Domain Model)。理解这些模式可以帮助我们更好地分析HCPC管理系统中的设计决策。 8. 源码学习: - 对于"jkjkljk解决好家伙...

    EJB设计模式

    12. **贫血模型和富模型(Anemic Domain Model and Rich Domain Model)** 贫血模型将业务逻辑放在服务层,而模型对象仅包含数据。富模型则将业务逻辑内聚到域对象中,提高代码的封装性和可维护性。 通过理解和...

    struts孙卫琴.rar

    学习Struts不仅要知道如何使用,还要理解如何遵循最佳实践,如分离表现层和业务层,使用贫血模型(Anemic Domain Model),以及如何有效地组织和管理ActionForm对象。 10. **实战案例** 书中可能包含多个实战案例...

    springMVC整合mybatis时的jar

    8. **最佳实践**:在实际开发中,应遵循一定的设计原则,如贫血模型(Anemic Domain Model)和富领域模型(Rich Domain Model),以及合理的分层架构,以保持代码的可维护性和扩展性。 综上所述,"springMVC整合...

    WPF中MVVM模式原理分析与实践

    - **解决现实世界的问题**:在开发过程中,开发者需要将现实世界中的实体抽象成模型,即Domain Object。这些模型可以是简单的数据载体(贫血模型),也可以包含业务逻辑(富血模型)。无论哪种形式,模型都无法直接...

    struts例子

    使用Struts开发时,应遵循一些最佳实践,例如:明确分离业务逻辑和表现层,使用贫血模型(Anemic Domain Model),合理组织Action和ActionForm,以及充分利用拦截器来增强功能。 综上所述,Struts框架通过其强大的...

    DDD领域驱动设计day01.pdf

    1. **领域模型**(Domain Model):领域模型是业务逻辑的抽象,它包含了业务实体、值对象、领域事件、聚合、工厂、仓储等元素。这些元素共同构成了一个反映业务规则的模型。 2. **统一语言**(Ubiquitous Language...

    JavaEye论坛热点月报 总第7期

    8. **贫血模型与领域模型** - 讨论了一个简单的示例,比较了贫血模型(Anemic Domain Model)和领域模型(Domain-Driven Design)在Java应用中的应用和优缺点。 9. **Spring中的DAO与Service** - 在Spring框架中,...

    java代码生成器

    3. **贫血模型(Anemic Domain Model)**:在生成的代码中,Entity类通常只包含属性,没有业务逻辑方法,这种设计被称为贫血模型,便于保持模型的简单性和纯粹性,但可能需要额外的服务层来处理业务逻辑。...

    wcl-cqrs-example:一个简单的CQRS示例

    查询模型通常使用贫血模型(Anemic Domain Model),其中对象主要包含数据字段,不包含业务逻辑。这些模型可以映射到视图层,用于展示数据。例如,我们可能会有一个`UserReadModel`,只包含用户的基本信息,用于检索...

    struts2项目

    11. **最佳实践**:在实际项目中,应遵循一些最佳实践,例如避免在Action类中使用静态变量,使用贫血模型(Anemic Domain Model)来分离业务逻辑,以及充分利用拦截器来封装共性功能。 12. **安全性**:Struts2的...

Global site tag (gtag.js) - Google Analytics