Transaction Script 和 Domain Model
一切都是对象吗?J2ee系统的开发应该都是采用面向对象技术,关键是怎么用的问题。
很久以前的一篇文章里,把一切都描述为对象,整个世界是那样的优美。我也深信不疑。
由于在我们的程序中,主要是针对数据处理和流程处理的,才知道用对象来表达不是那么自然。就涉及到了transaction script和domain model的概念,一个哲学问题!
Transaction script就是对表示层用户输入的处理程序。包括验证和计算,存储,调用其它系统的操作,把数据回传给表示层。
Domain model是所谓的域模型, 跟客观世界中的实体相对应。
Transaction script属于结构性思维,直观一些,在系统中如果domain model不是很明显,采用transaction script也是一个不错的选择。
Domain model属于OO思维,需要较强的抽象能力,习惯了就可以能够组织很复杂的逻辑,另外,我们必须考虑哪些行为是通用的、属于domain model的,哪些不是,可以通过一些xxxManager或者xxxController所实现的。
举一个例子,假如查看今天A银行到B银行的所有转帐记录,是列出A银行所有帐户对象来查看是否进行了转帐,还是从数据库中直接查询今天的转帐记录直观?
Transaction script还是有他的用处的。在我看来说,所有的程序都要通过Transaction script来组织,程度不同而已。
这个世界,除了对象,还是有对象间的关系、行为规则和记录(数据)的,观察的角度不同,就可以从不同的角度来组织系统,不一定需要用对象来表示。比如一个人是一个对象,档案所记录他一生的活动是什么,数据,是我们关注的一个方面,我们来查档案就够了,而不用去问这个人。
不排斥DB
在网上很多文章中,都会提到把系统想象成一个完美的oo世界,而是db只不过是一个持久化的手段而已。
我一直认为DB也是一个完整的世界(实际上也很完整),能够做很多事情,特别是在效率方案。
所谓采用OO和J2EE的系统,模拟现实世界,注重对象间的行为和关系,比较适合OLTP的应用。
而DB则是从数据角度来进行关注一个系统的,没有OO那么复杂的关系,处理效率很高,特别是在大批量数据处理和长事务处理的时候有自己的优势。在不存在明显错误的前提下,DB的实现一般要比OO语言要高效,只是从大的方向来讲有它自己的处理范围。
OO和DB需要一个适应、协作的过程。
你有多少系统是需要从不同数据库之间移植的,必要的时候,在j2ee方案中采用些db技术还是不错的选择。否则,就是从一个极端走到另一个极端,失之偏颇。
Transaction Script
What is it
很多企业应用可以看成一系列的事务,每一个事务可以通过使用一个Transaction Script来处理。
How it works
使用Transaction Script,我们可以专注于处理好每一个事务,而不必考虑其他事务的影响,所作的就是得到输入,查询数据库,处理事务,保存结果。
Transaction Script可以有两种方法组织成类。一种是将同一领域的几个Transaction Script放在一个独立的类中;另一种是采用Command模式,将每一个Transaction Script组织成一个Command基类的子类;当然,也可以不要组织成类,而使用全局函数的方式,但是类的方式更易于隔离数据。
When to use it
Transaction Script最大的优点和缺点,都是在于它的简单性。优点是代码的简单易懂,运行效率也不错;缺点是很可能出现代码重复,当然这个可以通过重构来减轻,更重要的是,随着企业事务复杂性的增加,Transaction Script就会变得力不从心。
Transaction Script下的开发有以下特征:对象类只包括数据,不包括任何事务相关的算法,往往就是数据库中表结构的类化;调用的Sql语句常常在Transaction Script核心函数中出现,当然这个是不好的设计,应该使用比如Table Data GateWay等模式,将Sql语句封装在wrapper中,来进行数据库交互,而核心函数直接访问wrapper的方法来进行事务处理
关于Transaction Script,Table Module,Domain Model 的选择从martin Fowler的那张图可以看出他的选择。我没有系统的研究过三者的差异,我感觉这对的。按照图上的含义,对于小型项目首选应该是Table Module,随着业务逻辑的复杂程度的增加Domain Model 将是首选。
在.NET环境中因为有ADO.NET类似“内存数据库”的支持使得使用Table Module很自然。Java环境中也可以通过组合纪录集的形式实现Table Module。对于批量类型的对象操作可以考虑Transaction Script,因为单个记录或者单个对象操作效率可能太低。
服务层本质上是facade,确实不应该包含业务逻辑。
用Domain Model替代Transaction Script
意图:
你的业务层采用Transaction Script模式实现
你希望将实现方式改为Domain Model模式
Bad Smells:
Long Method / Large Class??由于放置Transaction Script的service组件涉及全部业务逻辑的实现细节,其方法很容易变得冗长;如果对其使用Extract Method重构,则会使service实现类变得庞大。
Duplicate Code??不容易从现有的Transaction Script中找出可复用的代码,因此常常重复实现类似的逻辑。
Switch Statements??在领域对象有继承关系时,Transaction Script需要对不同类型的领域对象做不同的操作,此时容易造成基于类型的switch语句。
Data Class??领域对象只携带了数据,作为对象的职责不够。
重构过程:
使用Extract Method,消除Transaction Script中的重复代码。
使用Move Method,将领域对象固有的业务逻辑移到领域对象类中。
如果该方法需要使用DAO,则将DAO作为参数传入。
如果该方法需要使用其他service,说明该方法并不适合存在于特定领域对象类,而应该仍然存在于service组件中。
如果领域对象是一个继承体系,将业务逻辑移到其基类中。
如果第2步搬移的方法中有switch语句,使用Replace Conditional with Polymorphism消除之,将业务逻辑分配到领域对象的各个子类。
没有评论:
发表评论