`
yanhua
  • 浏览: 87487 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

读《设计模式解析》后对Dao层的重构

阅读更多
周末用了一天时间浏览了一遍《设计模式解析》这本书,其中很多观念令人耳目一新,根据作者反复提到的两条原则:

  • 找出变化并封装之。
  • 优先使用对象聚集,而不是类继承。

我突发奇想,对以前产品中的Dao部分做个简单的修改,当然,目前只是一个简单的设想。下面是以前的设计类图:



修改后的类图如下:

  • 其实第一种方案中也实现了“找出变化并封装之”的原则,但第二种方案中对变化的把握更细致更精确。
  • 表面上看,类的继承层次和数量并没有减少,但站在Dao的角度来看,优先使用了聚集,继承层次变得简单了。“优先使用对象聚集,而不是类继承”,有时候能够减少继承层次,有时则仅仅把继承再次封装起来了,继承本身并没有什么不好,关键是使用它的方式。这正如在创建对象时使用了大量的if... else,我们也许会想到用一个工厂封装之,其实if...else并没有消失,只是跑到工厂对象里去了。
  • 第二种方案中并没有创建一个SqlDialectFactory的类供OrganizationDao使用,其实OrganizationDao本身充当了这个角色。模式的重点不在于它的标准实现,而是要灵活运用他的思想。

您认为从方案一到方案二的更改有一定道理,还是画蛇添足,甚至是弄巧成拙呢?
分享到:
评论
13 楼 mewleo 2007-05-21  
楼主的思路与我最近思考的装备模型很像,
我也是围绕着DAO层考虑的,在想有更好
的方式。把对象包装起来,把属性对象和
动作对象聚合起来的方式管理业务模型。
如果有时间请看一下我的两篇文章,给我
提一点建议。

对象,你喜欢极品装备吗?
http://www.iteye.com/topic/79536
实现DDD装备模型
http://www.iteye.com/topic/81086
12 楼 hyhongyong 2007-04-17  
方案二和方案一中的接口变了?
如果是接口方法变了,那就是实现不同的功能了。
如果接口方法没变,只是换了个名称,本质上并无不同。

方案一中的工厂被方案二中的Dao替换
方案一中的Dao接口被方案二中的SqlDialect接口替换。
并没有什么实质差别。
11 楼 qinysong 2007-04-17  
嗯,同意xly_971223的观点

首先第二种方案是一个很优雅的设计,这种设计在某些系统中应该很值得借鉴的;

但是第二种方案相比第一种方案,它的最大价值是可以动态切换SqlDialect实现,而它的代价是增加了系统设计的复杂性,如果这种动态切换价值是可利用的,那么这种额外的复杂性就是值得的,但是在实际当中其实较少需要这种切换性

在实际开发当中我会按照XP的做法,采用简单设计
10 楼 xly_971223 2007-04-17  
看了一下第二种方法 觉得这种想法不错 但是实际应用起来会怎么样呢?
如果我们采用Jdbc,没有问题 可以很简单的切换到oracle或者sqlserver
但是如果要从jdbc到hibernate呢 ,只是一个OrgnizationDao肯定不够用 必须要抽象出接口用不同的api实现(或者其他方式),这样的话结构是不是太复杂了?
我还是觉得敏捷的方式比较好---增量设计。
9 楼 xly_971223 2007-04-17  
如果采用spring等框架,第一种方法中的工厂就是多余了
正如大师们预测的那样 单例 工厂等模式逐渐离我们远去
8 楼 yanhua 2007-04-16  
引用
我觉得是否采用方案二一个要考虑的因素是方案一的dao的职责是否超过一个.

有道理
7 楼 yanhua 2007-04-16  
我选择第二种方案的另一个原因是想以后可能使用Hibernate的Dialect包,因为Hibernate的Dialect包还没有研究,所以第二个图只是一个大概的示意……
6 楼 jamesby 2007-04-15  
引用
第一个方案中,为了实现不同数据库方言,于是引入了一个dao抽象类和两个子类,子类中必然大量方法类似,都是完成相同的dao逻辑。
第二个方案中,把数据库方言实现提取到了SqlDialect,再到dao中聚合SqlDialect,这样确实更加灵活,而且dao也变得简单了。由此可见优先聚合再考虑继承的好处了。
不错不错,受教了。
第一种方案也不是这样啊,如果使用标准的sql则,直接写如AbstractOrganization中,因此不存在你说的这种现象.

我觉得第一种方案好,第二种有些画蛇添足.

我们的目的就是为了适应不同的数据库.

第一种方案的dao子类也是这个目的,如果使用标准的sql的放入AbstractOrganization中.这个目的已经达到.

而第二种方案也是这样一个目的,表面上是优先使用组合,但实际上不是,因为Dialect也是有一个继承层次的!

我觉得是否使用聚合需要考虑以下因素,dao的职责是否单一,因为从楼主的例子看出dao存在多职责问题,而优先使用聚合则多数是将一个拥有多职责的类的一部分或者几个部分职责移出从而聚合方式.

而楼主是强行将dao的职责分成了与具体数据库有关的和与具体数据库无关两个职责,而我觉得是一个职责.

我觉得是否采用方案二一个要考虑的因素是方案一的dao的职责是否超过一个.

个人意见
5 楼 liuganquan 2007-04-15  
感觉第二种方案中在OrganizationDao中实例化 sqlDialect 不好,如果dao类多了的话,如果修改sqlDialect的实现的时候,o my god~~~
还是用factory 或者 setInterface 吧
4 楼 spiritfrog 2007-04-15  
第一个方案中,为了实现不同数据库方言,于是引入了一个dao抽象类和两个子类,子类中必然大量方法类似,都是完成相同的dao逻辑。
第二个方案中,把数据库方言实现提取到了SqlDialect,再到dao中聚合SqlDialect,这样确实更加灵活,而且dao也变得简单了。由此可见优先聚合再考虑继承的好处了。
不错不错,受教了。
3 楼 yanhua 2007-04-15  
图上的方法名写错了,把generate写成getnerate了。我觉得细类度可以使类的内聚性更高,也更易测试。当然,细到什么程度还是需要把握的,并非越细越好。
2 楼 yanhua 2007-04-15  
引用
我认为这两种方案本质上是一样,DAO模式本来就是策略模式(strategy模式)的应用,方案一将具体策略的实现推迟到了子类DAO中,而方案二只不过将访问数据库的具体策略封装到子类SqlDialect中并提供给DAO调用,看起来不同,但分析下结构却是一样的。

认真想了下,可以说方案二是更为细粒度的封装,方案一的封装停留在DAO对象的粒度上,而方案二将访问数据库的不同(变化点)进行了封装


这段评论很到位……

引用
细粒度带来的好像就是代码增多,比如在方案二中,DAO、SqlDialect和子类SqlDialect的方法要保持一致。

在方案二中DAO和SqlDialect的接口并不一样……
1 楼 dennis_zane 2007-04-15  
我认为这两种方案本质上是一样,DAO模式本来就是策略模式(strategy模式)的应用,方案一将具体策略的实现推迟到了子类DAO中,而方案二只不过将访问数据库的具体策略封装到子类SqlDialect中并提供给DAO调用,看起来不同,但分析下结构却是一样的。

认真想了下,可以说方案二是更为细粒度的封装,方案一的封装停留在DAO对象的粒度上,而方案二将访问数据库的不同(变化点)进行了封装,细粒度带来的好像就是代码增多,比如在方案二中,DAO、SqlDialect和子类SqlDialect的方法要保持一致。

相关推荐

Global site tag (gtag.js) - Google Analytics