该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-04-18
1. SFSB表示鸭梨很大
2. DDD与OO没有绝对关系,分层模式做的好,也有很多可以实践OO的地方。 3. 没有完美的理念,只有残缺的人. |
|
返回顶楼 | |
发表时间:2011-04-18
引用 我正在我们公司推进DDD。关于技术实现,我觉得问题不大。想想前人当年没有hibernate, spring等现代化工具时,就能做到,我们现在有更多的选择,不可能做不到的。
觉得问题不大,并不代表就能很顺利,也不代表是最优方案。 引用 一般应用DDD,要对分层,从上到下依次为 用户界面层 -> 应用层 -> 领域层 -> 基础设施层。
你说的service层估计指的是应用程,这一层把用户输入数据转化为领域认识的数据,把领域返回的数据变成用户界面用的数据,这一层知道哪些用户操作执行哪些领域操作。 那你这个应用层和贫血模式就的Service层几乎差不多。 引用 领域层,就是比较纯的面向对象方式组织的代码了,你说的多个领域对象之间协调是很自然的事情,应该不会有问题。为了减少技术框架对实现领域带来的限制,尽管我们使用hibernate, 但是我打算彻底分离实体和数据库表映射的职责。也就是说,一个实体,就是代表了一个领域对象,而不是一张数据库的表,不作为hibernate的表映射类,不打@javax.persistence.Entity。而映射表的类,放到基础结构层。spring的话,对领域的侵入性相对比较小,只是会因为要注入依赖,而给类添加了一些看起来像关联关系的域,不过只要分清楚,还可以接受。我已经在我们的应用的一小部分应用了这一方式,没有什么问题,后面打算大规模推广。
我的理解,你是在entity之上再弄一层,搞一个大的domain对象来面对业务。你并没有回答我的一些问题,如业务逻辑的方法,你们是放在哪里,在你所谓的应用层,还是你的domain里?如果是放在domain里,那么多个domain里面的各种方法互相调用,要保持事务一致性的时候,怎么处理?如果是放在应用层里,那和贫血有什么区别?还不是一样。 引用 我深刻的体会到,领域模型里的实体并不和数据库的表有着简单的一对一映射关系。一个实体,可能会映射到多张表,一张表,也有可能会映射到多个实体,而且表里的字段和实体的属性也不能一一对应。因为,领域实体力求表达领域问题,而数据库的表,更关注于数据的存取便利和性能等。把这两个职责分离后,领域和数据将各自能比较自由的发展。
当domain多时,相当于封装了一个更大的对象。这样就一定比hibernate里的关联关系的映射好吗?而且如果你不映射到相关数据库,你怎么做?手工封装一下domain结构?就算你借助工作吧,那就会到最原始的db table-->javabean(大domain)转换上了。 |
|
返回顶楼 | |
发表时间:2011-04-18
引用 很喜欢这类文章 LZ威武
不过不大明白的是。LZ已经说了。 富血模型对复杂事务的支持不大好, 但是LZ又说贫血模型适合做简单的业务。 这是不是冲突了? 我觉得“复杂的业务”很多时候都是多个领域对像之间的交互,这之间肯定会涉及事务。所以应该是贫血模型适合做复杂原业务。 当把逻辑方法放到domain里时,也就是说不再加一层service层时,各domain方法间的事务一致性是不好控制的。我没有说贫血模型适合做简单的业务(可能你看到的是前人总结的观点),我的观点和你一样是贫血更适合做复杂的业务。 |
|
返回顶楼 | |
发表时间:2011-04-18
abiandbel 写道 fireflyc 写道 哎,看了楼主的介绍我觉得,楼主对领域驱动设计认识似乎是有问题的,而且我感觉基本上很多人都是存在这样的一个误区。
认为service和entity和DAO合并在一起,就是领域驱动了,比如之前是 Student,StudentDAO(或者泛型DAO),StudentService现在只有一个Student来干所有的事情。 我觉得持有这种观点的人是对DDD的理解有问题的,DDD中最为突出的5辆马车,Entity,Value Object,Factory,Service,Repository,这里可是也有entity也有vo,也有service的。只此一例来证明楼主对DDD的理解有偏差。 很同意你的观点,貌似现在很多人认为 service和entity和DAO合并在一起,就是领域驱动了 downpour 写道 任何的开发方法和模式,都不能和程序开发中最基本的最佳实践相违背。在Java中,让Domain Object和Service Layer过度膨胀都是错误做法。只有两者结合,才能写出可维护的代码来。程序员在这里需要权衡的,是哪些逻辑应该放在Domain Object里面,哪些逻辑应该放在Service Layer中。 老大说的很到位,非常同意。DDD更加关注职责划分。Domain Object有什么,Service Layer有什么,只有职责都划分清楚了,才能弄的清楚。当然DDD还有其他方面。 1.没有人完全认为service和entity和DAO合并在一起,就是领域驱动了。但是如果你富血也有service,也有entity,dao,逻辑也放在service。那和贫血就没什么太大的区别了。说句不好听的话,就是在玩概念! 2.马P不要乱拍。职责分清肯定是在分析的时候做的,不管是富血还是贫血。 |
|
返回顶楼 | |
发表时间:2011-04-18
sulong 写道 下面是一些示例代码,
//以下是UI层代码 @Component public class SomeAction { private SomeApp someApp; private String id; public String execute() { try { this.someApp.someBusinessMethod(this.id); return "success"; } catch (SomeBusinessException e) { ... return "fail"; } } @Autowired public void setSomeApp(SomeApp someApp) { this.someApp = someApp; } ... } //以下是应用层代码 @Component public class SomeApp { private SomeRepository someRepository; public void someBusinessMethod(String id) { SomeEntity someEntity = this.someRepository.findById(id) someEntity.executeSomeBusiness(); } @Autowired public void setSomeRepository(SomeRepository someRepository) { this.someRepository = someRepository; } } //以下是领域层代码 public interface SomeEntity { public void executeSomeBusiness(); } public class SomeEntityImpl implements SomeEntity { private SomeTable someTable; private SomeRepository someRepository; public SomeEntityImpl(SomeTable someTable) { this.someTable = someTable; } public void executeSomeBusiness() { this.someTable.setSomeAttribute("someValue"); ... this.someRepository.update(this); } @Autowired public void setSomeRepository(SomeRepository someRepository) { this.someRepository = someRepository; } public SomeTable getSomeTable() { return this.someTable; } } @Component public class SomeRepository implements ApplicationContextAware { private SomeDao someDao; private ApplicationContext applicationContext; public SomeEntity findById(String id) { SomeTable someTable = this.someDao.findById(id); SomeEntityImpl someEntityImpl = new SomeEntityImpl(someTable); this.applicationContext.getAutowireCapableBeanFactory().autowireBean(someEntityImpl); return someEntityImpl; } public void update(SomeEntity someEntity) { SomeEntityImpl someEntityImpl = (SomeEntityImpl) someEntity; this.someDao.update(someEntityImpl.getSomeTable())); } @Autowired public void setSomeDao(SomeDao someDao) { this.someDao = someDao; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } } //以下是基础设施层代码 @Entity @Table(name = "some_table") public class SomeTable { @Id private String id; ... } @Component public class SomeDao extends HibernateDaoSupport{ ... } 分层必然会使某些代码变得麻烦,但是,我觉得当领域足够复杂的时候,是有必要牺牲的。 我不知道这是不是DDD正统的代码。但从上面的代码来看,分层(包括service,dao还是有的,只不过是换了个概念)。你上面的代码无非就是一个简单的crud,就让人感觉很麻烦!实在看不出来比贫血的应用好在哪里。 当有一些复杂的业务协作时,如各个模块的互相协作,并要保持事务,我想你的app层又该回到过程式的了,不那么oo了。 |
|
返回顶楼 | |
发表时间:2011-04-18
fireflyc 写道 peterwei 写道 fireflyc 写道 哎,看了楼主的介绍我觉得,楼主对领域驱动设计认识似乎是有问题的,而且我感觉基本上很多人都是存在这样的一个误区。
认为service和entity和DAO合并在一起,就是领域驱动了,比如之前是 Student,StudentDAO(或者泛型DAO),StudentService现在只有一个Student来干所有的事情。 我觉得持有这种观点的人是对DDD的理解有问题的,DDD中最为突出的5辆马车,Entity,Value Object,Factory,Service,Repository,这里可是也有entity也有vo,也有service的。只此一例来证明楼主对DDD的理解有偏差。 我承认我对DDD了解不深。那么,DDD应该是吧数据和逻辑放在一起吧?service层应该不管逻辑的事吧,应该只是浅浅的一层。那么dao,service是可有可无吧,从spring roo可以看到一斑。如果你有DDD实践经验,那么你认为DDD在国内是否已经成熟,是否可以在实际的项目中推广了?推广的难度是什么?为什么大家还在用贫血的模式? 可以先这样理解DDD,它是一种设计方法,与传统的面向数据库设计对立的方法。当面对一个系统的时候不应该想到的是有哪些表,先折腾数据库结构;这种设计方法只能让所有的业务逻辑更加凌乱系统模块各个都紧密的耦合在一起。DDD的做法是先进行系统的分析,识别出一些对象,Entity VO Service Repository之类的,其实就是一个为对象分配职责的过程,注意这个中间不涉及到任何数据库相关的东西,没有表结构的概念。所以重要的问题不在于用的是什么roo还是ruby之类的,重要的是你的设计是否真正的做到了不是以数据库为中心的设计,这个才是DDD真正的意义所在。 你就扯吧。要是像你这样的就是DDD,那我想大多数人都在搞DDD了。现在一般OOAD,都是面向业务需求划分domain,进行系统分析,划分各个模块职责(service就相对于某问题域的代理),然后才转化为数据库。很少有人一开始就搞数据库。什么意义都没有用,落地应用,并能提高效率才是王道。要不然搞了一堆理念,搞起来更花时间,让开发人员更不爽,项目时间成本也上去。这样的理念如果不能改进,还是不要的好。 |
|
返回顶楼 | |
发表时间:2011-04-18
fireflyc 写道 peterwei 写道 fireflyc 写道 哎,看了楼主的介绍我觉得,楼主对领域驱动设计认识似乎是有问题的,而且我感觉基本上很多人都是存在这样的一个误区。
认为service和entity和DAO合并在一起,就是领域驱动了,比如之前是 Student,StudentDAO(或者泛型DAO),StudentService现在只有一个Student来干所有的事情。 我觉得持有这种观点的人是对DDD的理解有问题的,DDD中最为突出的5辆马车,Entity,Value Object,Factory,Service,Repository,这里可是也有entity也有vo,也有service的。只此一例来证明楼主对DDD的理解有偏差。 我承认我对DDD了解不深。那么,DDD应该是吧数据和逻辑放在一起吧?service层应该不管逻辑的事吧,应该只是浅浅的一层。那么dao,service是可有可无吧,从spring roo可以看到一斑。如果你有DDD实践经验,那么你认为DDD在国内是否已经成熟,是否可以在实际的项目中推广了?推广的难度是什么?为什么大家还在用贫血的模式? 可以先这样理解DDD,它是一种设计方法,与传统的面向数据库设计对立的方法。当面对一个系统的时候不应该想到的是有哪些表,先折腾数据库结构;这种设计方法只能让所有的业务逻辑更加凌乱系统模块各个都紧密的耦合在一起。DDD的做法是先进行系统的分析,识别出一些对象,Entity VO Service Repository之类的,其实就是一个为对象分配职责的过程,注意这个中间不涉及到任何数据库相关的东西,没有表结构的概念。所以重要的问题不在于用的是什么roo还是ruby之类的,重要的是你的设计是否真正的做到了不是以数据库为中心的设计,这个才是DDD真正的意义所在。 这个说出了核心 |
|
返回顶楼 | |
发表时间:2011-04-18
sulong 写道 下面是一些示例代码,
//以下是UI层代码 @Component public class SomeAction { private SomeApp someApp; private String id; public String execute() { try { this.someApp.someBusinessMethod(this.id); return "success"; } catch (SomeBusinessException e) { ... return "fail"; } } @Autowired public void setSomeApp(SomeApp someApp) { this.someApp = someApp; } ... } //以下是应用层代码 @Component public class SomeApp { private SomeRepository someRepository; public void someBusinessMethod(String id) { SomeEntity someEntity = this.someRepository.findById(id) someEntity.executeSomeBusiness(); } @Autowired public void setSomeRepository(SomeRepository someRepository) { this.someRepository = someRepository; } } //以下是领域层代码 public interface SomeEntity { public void executeSomeBusiness(); } public class SomeEntityImpl implements SomeEntity { private SomeTable someTable; private SomeRepository someRepository; public SomeEntityImpl(SomeTable someTable) { this.someTable = someTable; } public void executeSomeBusiness() { this.someTable.setSomeAttribute("someValue"); ... this.someRepository.update(this); } @Autowired public void setSomeRepository(SomeRepository someRepository) { this.someRepository = someRepository; } public SomeTable getSomeTable() { return this.someTable; } } @Component public class SomeRepository implements ApplicationContextAware { private SomeDao someDao; private ApplicationContext applicationContext; public SomeEntity findById(String id) { SomeTable someTable = this.someDao.findById(id); SomeEntityImpl someEntityImpl = new SomeEntityImpl(someTable); this.applicationContext.getAutowireCapableBeanFactory().autowireBean(someEntityImpl); return someEntityImpl; } public void update(SomeEntity someEntity) { SomeEntityImpl someEntityImpl = (SomeEntityImpl) someEntity; this.someDao.update(someEntityImpl.getSomeTable())); } @Autowired public void setSomeDao(SomeDao someDao) { this.someDao = someDao; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } } //以下是基础设施层代码 @Entity @Table(name = "some_table") public class SomeTable { @Id private String id; ... } @Component public class SomeDao extends HibernateDaoSupport{ ... } 分层必然会使某些代码变得麻烦,但是,我觉得当领域足够复杂的时候,是有必要牺牲的。 这样的分层的路我也曾经走过,结果就是大量的类中剩下大量的垃圾代码,正在有用的代码没几行。如此增加开发人员的工作量得不偿失,特别是需要修改业务的时候。总结下来,必要的分层是界面/业务,其它的分层都是需要根据实际情况而定的,不能一概而论 |
|
返回顶楼 | |
发表时间:2011-04-18
数据库就像建楼的地基,你建大厦开始就需要考虑进去这部分的特性,而且必须考虑,这是所有业务最后能落地的部分,可用效能安全都会依赖这块的设计
企业应用即使你不以数据库为中心,至少也应该以数据和数据流向为中心,这和面向数据库设计并不矛盾 所有的设计都是平衡的产物,很不幸DB是其中有一票否决的成员,看看现在云的研究论文都集中在哪一端 |
|
返回顶楼 | |
发表时间:2011-04-18
各位,不如把《领域驱动设计》那本书看一看,如果连这一方法学的经典书藉都没有看过,这样讨论没有多大意义。
DDD的好处不仅仅体现在代码上。它要解决的领域与实现的矛盾,不是具体的技术手段。具体的技术手段,就只强调独立的领域层代码,及模型绑定代码。其它的都是一些具体的技巧了。 |
|
返回顶楼 | |