Posted on 2005-07-17 02:31
冰火 阅读(3061)
评论(48) 编辑 收藏
一般系统可划分为三个层次:表现层,领域层,数据源层。通常还可以将领域层提取出服务层来。
根据不同的应用场景,不同的架构设计将会有不同的层间交互形式。
常见的有如下几种:
模式一
UI->Domain->Data Source
此模式是很典型的一种交互方式,简单纯粹,上层依赖于下层,没有跨层调用。
模式二
UI->Domain->Data Source
UI->Data Source
此模式是不太纯粹的交互方式,允许跨层调用,但在实践中运行良好。
模式三
UI->Domain<-Data Source
此模式是典型的采用依赖倒置原则的交互方式,Domain将不再依赖于Data Source,实现方式通常是在Domain定义Data Source接口。
模式四
UI->Service->Domain->Data Source
此模式是引入服务层之后的典型交互方式,类似于模式一。
模式五
UI->Service->Domain->Data Source
Service->Data Source
此模式类似于模式二。
模式六
UI->Service->Domain<-Data Source
此模式类似于模式三。
模式七
UI->Service->Domain<-Data Source
Service->Data Source
此种模式是模式二和三引入服务层后演化来的。
还有很多其他的模式和变种,在此仅列出比较常见的一些。
以上各种模式没有好坏,高低之分。只有适不适用的问题。
每种模式都有它的运用场景,要根据具体情况具体分析。
简单的写了一点,望不吝批评指正。
Feedback
@风一样的狂徒11
呵呵,写这篇随笔,所以晚了点。你也起的挺早吗!
也顺便说一下,下次不要叫“楼猪”了。
不错, 模式3或者7可能是最适合于一些大型系统的.
提醒一下...
Domain是需要与Data Source交互的,否则怎么获取Data呢?
UI->Domain<->Data Source
只是主次区别而已了,呵呵
@非非.Net
Domain是可以不依赖于Data Source的。
而且在模式三和模式七中是不应该依赖于Data Source的。
依赖倒置吗。否则就会有双向依赖了。
@idior
好吧,那就叫领域层或是Domain layer吧
佩服你们的专业精神!
不过怎么不发表一点专业的看法,意见呢?
你们有何心得也可以不吝分享吗!
不是, 在我理解中好像domain不是一个层的概念.
一般你所说的domain Layer是叫做business Layer业务逻辑层
至于Domain model是不是有Domain Layer好像不太确定, 如果在某本书中却有此说法,望指点一下.
最近我刚好在写这方面的文章, 很快就能发布. 到时一起讨论一下.这篇随笔的内容比较抽象, 不太方便评论.
UI->Domain<-Data Source ?
个人对这个模式比较陌生
盼idior的文章快点发布,呵呵
@idior
企业应用架构模式就有这种说法啊
At the same time that client-server was gaining popularity, the object-oriented world was rising. The object community had an answer to the problem of domain logic, move to a three layer system. In this approach you have a presentation layer for your UI, a domain layer for your domain logic, and a data source. This way you can move all of that intricate domain logic out of the UI and put into a layer where you can objects to properly work with it.
当然也可以叫做Domain logic layer或者Business logic layer,这其实不是至关重要的。能理解就行了。
@idior
Domain model不是Domain layer!
Domain model和Transaction script,Table Module只是Domain layer的领域逻辑的组织方式罢了。
@idior 这篇随笔的内容比较抽象, 不太方便评论
也对,不过我比较喜欢这种简洁明了的形式,也喜欢读这种形式的文章。
能引起思考就好。
希望这片随笔能引起大家的思考,也希望读这片随笔的人能够认真的思考每种模式。
Domain和Business可能是不同的习惯称谓,实际应该是相同的含义,我是把两者等同看待的,除非特定环境下明确说明其它含义
@happyprogram
没错,关键是理解意思就行了,称谓其实很多的。
@happyprogram
也巧 我的文章就是说这个的 不过在里面Domain和Business是有区别的.
针对每种模式,其运用场景,面临的问题,技术抉择等等,希望下次能有机会,有时间单独开篇谈一谈我的看法。
在我看来,分层的目标是减少依赖。不过如果一定要总结各层的模式我觉得是很不现实的,我个人从来不依赖模式,但是强调变与不变之间的契约。如果不变的部分作为各层间的会话基础,层与层之间完全没有依赖的必要。Spring不就已经实现了吗?
关于这不变的部分,如果太小我们称为API或者框架(Framework);如果不大不小我们称为架构(Architecture);如果再大一些我们称为平台(Platform)。
我们为什么要受模式约束来捆住自己?
其实 就分层而谈。
窃以为一切都应该依赖于业务逻辑。业务逻辑是中心, 至于是否能做到,从多大程度上做到,就受当前的技术,以及开发者的水平影响。
模式只是给你提出一些前人的建议, 在你领悟其中的内涵之后是可以摆脱模式的束缚。 但是在你尚未领悟之前, 模式绝对是你值得参考和研究的对象。
双鱼座可能已经明白了其中的道理,自然会视模式于不顾,但你也要考虑其他人的情况。
@iditor
同意你的说法
@双鱼座
我不知道你是否真的达到了如此高的境界,可以视模式于不顾。
我想即使Martin Flower也不敢说这样的话吧。
我们为什么非得用模式来束缚自己呢。
另外,我认为分层的目标并不只是减少依赖,分层的好处我就不用多说了,Martin Flower已经说得很清楚了。
并不是什么依赖都没有的模型就是最好的模型,这也是不现实的。
很多模型或架构本身之间无所谓好坏问题,关键是适不适用于当前的应用场景。
Spring也不是用来干这个的。
破除不稳定的依赖才是有必要的。
@idior:我明白你的意思。的确,了解模式(Pattern)是必要的,但是自如地运用才是最终的目标。从这个意义上,认识模式只是基础。但是本文讲述的模式是层间交互模式,此模式非彼模式。这个模式的实质并不是模式,而是交互、契约、应用协议。
为什么你会认为以业务逻辑为中心?那是因为业务逻辑才是变的,其余的基本上是不变的或者相对不变的。
@双鱼座
我明白你的意思。的确,了解模式(Pattern)是必要的,但是自如地运用才是最终的目标。从这个意义上,认识模式只是基础。
同意你的看法!
但是本文讲述的模式是层间交互模式,此模式非彼模式。这个模式的实质并不是模式,而是交互、契约、应用协议。
你这么理解也无妨,其实模式是很广义的。有设计模式,架构模式等等。我所说的也可以叫做模式的。
为什么你会认为以业务逻辑为中心?那是因为业务逻辑才是变的,其余的基本上是不变的或者相对不变的。
以领域逻辑为中心我觉得是对的。
1、领域逻辑是核心,非核心的东西依赖于核心的东西。
2、领域逻辑相对于其他的东西来说是更稳定的,而且一旦领域逻辑变了,将对整个系统产生根本的影响。
@冰火:
所谓的层间交互模式并不是真正的模式,即使是真正的模式也不是绝对必要的。事实上在GOF总结出Design Pattern之前,一样有大量的天才写出天才的软件来。你理解的模式和我理解的模式不是一回事,自然在心目中的份量是不同的。
减少依赖并不象你想象的那么简单。当一个模型交付以后发生了变动,而业务几乎不受影响或者只是局部受到影响,这样只需要很小的或者局部的改动就可以继续胜任新的业务,这是分层的目的,也就是减少依赖。记得Martin也是用OSI七层协议来描述分层的逻辑,其实质也是减少非耦合层间的依赖。
关于Spring,我倒要请教了,你觉得他是干什么用的?除了IoC之外,意义何在?
对模式的理解不要太局限, 不是一定要能画出class diagram的才能叫模式. 模式有很多层次: 构架层次的模式, 设计层次的模式, 编码层次的模式... Client/Server三层结构也是一种模式.
◎双鱼座
有关spring我马上会提到 :)
为什么以业务为中心?
业务才是我们真正需要解决的问题。 所有的软件之所以不同。 很大程度上是因为业务的不同。所以业务(Domain Model)是软件的核心。
以业务为中心, 其他的依赖于业务,比较理想的状态是当业务变化时,
其他自动调整以适应业务的变化。至于这种自动化的程度有多高,就看框架以及设计者的水平了。
模式只是一种在特定环境下解决特定问题的(比较好的)方法。
模式更多的是一种经验的体现。
@小陆:
我完全能够接受楼主所采用的“模式”这个概念,事实上,我也经常使用与Design pattern相悖的“模式”概念。只是不能接受将层间的交互方式列出有限的几种“模式”来。而且,我的评论自始至终我都没有离开“分层”这个中心,只是楼主和idior错误地理解了我的意思,将焦点移到了“模式”这个概念上。
其实有关模式的讨论是因为这句话
--
从这个意义上,认识模式只是基础。但是本文讲述的模式是层间交互模式,此模式非彼模式。这个模式的实质并不是模式,而是交互、契约、应用协议。
--
既然大家都知道什么意思,就没必要就这个说下去了。
不过让更多的人明白模式的含义也是件好事。
@双鱼座
减少依赖并不象你想象的那么简单。当一个模型交付以后发生了变动,而业务几乎不受影响或者只是局部受到影响,这样只需要很小的或者局部的改动就可以继续胜任新的业务,这是分层的目的,也就是减少依赖。记得Martin也是用OSI七层协议来描述分层的逻辑,其实质也是减少非耦合层间的依赖。
减少非耦合层间的依赖当然是正确的啦,我并无异议。我是说分层并不仅仅是这个目的。
关于Spring,我倒要请教了,你觉得他是干什么用的?除了IoC之外,意义何在?
我是说Spring不是用来破除层间依赖的。我说了破除不稳定的依赖才是必要的。
坦率的说我对Spring没有深入研究,我觉得隔离变化是其中重要的一点。
你有和高见?
@idior
既然大家都知道什么意思,就没必要就这个说下去了。
不过让更多的人明白模式的含义也是件好事。
同意!
自然分层的目的不仅仅是解除非耦合层间的依赖,从某种意义上讲,这不是目标,只是一种指征甚至只是一种手段或者方法而已。事实上,没有良好分层的系统几乎无法做单元测试,这是XP推崇者无法接受的。
昨天和一个朋友讨论JUnit和NUnit,他说,他采用的持久层框架是Hibernate,但是却使用DBUnit来做单元测试。我严重吃惊!难道Hibernate没有提供一个JUnit的扩展,以杜绝测试代码跨越持久层吗?事实上Hibernate的确没有提供。
@ 双鱼座
你指的何种程度的扩展?
既然hibernate已经实现了映射成对象的功能,那么基于对象进行测试使用XUnit的基本功能就足够了啊? 你说的扩展是何意见?
保持系统的可测性非常重要,特别是在离开容器和框架下的可测性,更是一种追求.
@idior:
其实我所谓的测试依赖与你的可测试性原则是一样的。对于被测试对象而言,测试对象就是一个逻辑上的层。
测试对象只能依赖目标框架(领域模型)和测试框架(例如XUnit)。如果再依赖某个持久层就不合理了。可是确实是需要在测试中使用持久层的API,这时你可以使用同时封装了持久层和XUnit的一个新框架。当然这个框架就是XUnit的扩展,它接管了XUnit的所有职责,同时还提供了一套基于框架的初始化机制、测试调用机制、清理机制和断言机制,完全仿真所需要的容器。换句话说,如果持久层换了,我的测试代码不必动,只要动XUnit的持久层扩展就行了。按TDD原则,测试代码是事先写好的,这时候很可能测试对象只是一个抽象的接口,直接依赖某个持久层的后果是相当严重的。
当然你可以不必这么严格,但是无论如何,持久层已经将数据层封装起来了,你不可以使用DBUnit来越过Hibernate去直接访问数据层。因为这样你至少需要在测试代码中了解Hibernate持久化的细节,这直接有悖于分层的目标了。
不知道你是否明白我的意思?
Sorry,有点跑题了。
我个人一直倾向于模式3,UI->Domain<-Data Source,在必要的时候加入service层,虽然这个方式在规模小,周期短,一次性的项目中效果并不是很好,但我认为养成这样的习惯是很重要的。
我同样认为应该一切以业务逻辑为中心,我们做应用,就是为了实现现实的需求。业务变,其他变是理所应当的。UI,DataAccess都是由业务派生而来的dd。
而以我们的努力最大程度做到的只是在业务没有发生变化时,对于UI,数据访问层等修改的影响只局限在本层,而这一切都要依赖于业务层对上提供的业务服务接口和对下提供的数据访问接口。
继续评论。
@simonw:
个人感觉你比较悲观和消极(恕我妄加猜断了)。实现合理、现实的业务需要应该只是最低的标准。业务变化后是其它各层主动去适应才应该是最高的追求。要不然,不要分层反而可能换来较高的运行效率。
@双鱼座
严重同意双鱼座对测试的看法,最近做的东西也是在应用NHibernate后,对于做单元测试也是有不少问题,我们的做法是在Nhibernate上做了一个简单的封装,然后使用封装后的接品。但在准备测试数据和改变测试数据上比较困难,直接操作数据记录和造成和Nhibernate的状态不同步,现在解决办法是在做单元测试时显示刷新。
@双鱼座
基本同意你对测试的看法
但运用依赖倒置后,如模型3,测试代码会很难写吗?
另外关于其它层主动适应业务逻辑变化。我持保留态度。
往往很多时候是很难做到的。
@双鱼座
其它层主动适应业务逻辑变化,能举个简单的例子么?
而我能想到的例子,例如,银行利息算法发生改变这样的业务变化无需更改其他层。但更多情况时增加新的业务逻辑,其他层如何去智能的适应呢,人尚且无法预计,程序怎能做到?或许我理解错了你的意思?
我认为我们最多能做的就是对需求变化的预计,从而设计出适合扩展接口,当业务发生变化的时候使得各层的变化尽量小。
@simonw:
最典型的例子应该是PropertyGrid吧。任何object都可以通过PropertyGrid显示出来。控制PropertyGrid显示的并不是object自身,而是元数据及其相关的支持元素,TypeConverter、TypeEditor和Designer等等。PropertyGrid只是IDE表现层的一部分,你可以利用这些元数据来轻松地重写你自己的PropertyGrid。当你重写一个TypeEditor的时候,即使你其它地方没有任何变化,你的PropertyGrid会相应变化。
注意,这只是一个例子,真正实现UI随业务层变化及配置的变化而变化,会比PropertyGrid复杂很多。所以,我说是一种追求,而不是已经实现了。
顺便说一句,我的一些工具就采用了ComponentModel类似的设计期支持来实现UI。至于Web类型的UI,我觉得需要花更大的代价来实现。这不是什么创新,根本就是模仿。
@双鱼座
有追求总是好的。呵呵
谢谢每一位参与讨论,以及每一位阅读本文的同仁。
交流总是富有意义的。希望以后能和你们多交流,也希望能写更多的文章给大家分享,无论对的,错的。
很想看看模式3的实例。我研究了半天不知道怎么实现!