Month: June 2009

[Enterprise SOA] OO与SOA的阻抗

以前一直有就这种想法,今天发现“Enterprise SOA”这本书中明确地把它提出来了: “面向对象强制性封装数据和功能,而面向服务通常认为数据和功能是分开的” 这让人联想起 贫血模型与充血模型旷日持久的争论…… 还有, "对象的粒度一般比较小,这会在分布式系统中导致很多远程调用"

Portlet V.S. Servlet

Portlets are similar to servlets, in that:    1. Portlets are managed by a specialized container.    2. Portlets generate dynamic content.    3. A portlet’s life cycle is managed by the container.    4. Portlets interact with web client via a request/response paradigm. Portlets are different from servlets, in that:    1. Portlets only …

Portlet V.S. Servlet Read More »

从单元测试的角度看,抽象类与接口有很大区别

从单元测试的角度看,抽象类与接口有很大区别;下面将会提到,即使有了抽象类,也应该做一个接口。 为什么这么说呢?我们都知道单元测试时往往需要Mock一个被依赖的接口,并且要实现这个接口中的相关方法。 举例来说,如果我们要测A类,而A调用了B.method1(),那我们的Mock类就要实现B接口,并实现method1()方法 但如果被B不是一个接口名,而是一个无接口的具体类(也就是说没有按接口编程),那也不难办,我们就继承B,并覆盖method1()方法,可能还要覆盖构造方法,如果B中的构造方法依赖了别的资源。 这样做已经有点别扭了。 但如果B是一个抽象类,那就更别扭了。因为你不但要覆盖B的method1()方法和B的构造方法,还要实现B的抽象方法!不过,如果B的抽象方法就是method1(),那就不必了。 那么从中可以看出抽象类与接口的什么区别呢? 区别就是 接口的抽象方法代表真正的契约,而抽象类中的就未必。接口中的抽象方法总是为他人服务的public方式,而抽象类中的抽象方法可能只是protected的,交给子类实现而已。 再进一步说, 接口和抽象类都体现了一种抽象,一种等待子孙来实现的抽象;但接口还代表了一项服务。 而单元测试时的Mock是对服务的一种Mock,显然,这时候我们更偏好接口。

关于Domain Model的对谈录之四: 充血与贫血的折衷

A:持久化的问题搞得充血模型很头痛。于是有人提出了一个折衷的模型,即 与持久化无关的业务逻辑放到Domain Object中,有关的逻辑则放到Transaction Script中。robbin对种模型有非常好的阐述,这种模型的可操作性也的确比较强。 B:嗯,其实以前我也一直是这样做的。不过,这种模型还可以再精化一下,就是 尽量在Domain Object中做好所有的业务逻辑,然后Transaction Script只处理持久化。具体来说,就是先通过Transaction Script取出所有相关Domain Object,然后让这些Object在内存中互相交互,互相改变状态,以及产生新对象,最后再通过Transaction Script对这些新旧对象进行持久化。 A:听起来不错哦!职责分离的比较清楚,Domain Object和Transaction Script各司所长。你实践起来怎么样? B: 折衷模型在大多数情况下都很好,因为大部分业务逻辑的OLTP处理都只牵涉到少数的Domain Object,因此在Transaction Script中对它们进行CRUD都不会很占用过多篇幅,代码整体上还是很简洁的。 A:那在少数情况下呢? B:很讨厌。目前按我的经验有两种情形让我很烦:    1. 如果参与处理Domain Object的类型有很多种,折衷模型就会很可笑。如果你的Script中要一次性取出很多种对象,那么其中很多种对象对你来说可能都是远亲,你的Script本不应该去找它们的。但你却找它们了,这意味着IOC被严重破坏,代码的质量可想而知。    2. 如果参与处理的Domain Object实例数很多,折衷模型还会遭遇性能问题。比如一个批量操作,正常流程是取一个做一个,然后立即更新到数据库,对象从内存中清除;但现在你要取一整批,然后做一整批,最后再批量更新到数据库,这不是内存老虎是什么?很可怕的! A:很好! 那遇到这两种情况你怎么办? B:能怎么办?只能干脆把业务逻辑全部从Domain Object里转移到Transaction Script中来,这样首先可以避免性能问题(做一个存一个),而且还可以通过多个Script对象之间的协作来完成复杂的业务逻辑。 A:但这就完全退化到了贫血模型了。 B:是啊。所以,还是干脆点,就用充血模型好了。 A:呵呵。不管怎么样,从你上面举的例子中可以看出, 业务逻辑越复杂,Domain Model的性价比就越高。 B:为什么? A:因为业务逻辑越复杂,一次业务计算牵涉到的业务对象的种类和实例数就会越多,Transaction Script就会变得越来越全能,也越来越臃肿(反IOC),也就越来越反OO,也就越来越难于适应需求的变化。

关于Domain Model的对谈录之三: 充血模型与Domain Object的持久化

A: 充血模型中,Domain Object的持久化远远不如贫血模型来得清爽 B:你这里的“清爽”是上海话吧? 详细说说,为什么不够清爽?你不是说充血模型“老清爽”吗? A:从业务逻辑的OO化来说,充血模型的确更清楚简洁;但在持久化问题上,可以说“很别扭”。第一个问题是循环调用问题:Domain Object要调用持久化的DAO接口,来把自己持久化;而DAO接口又要把Domain Object作为参数来做CRUD操作。 B:嗯, Stutent.save()中要执行studentDAO.save(this),而StudentDAO.save(Student)的参数就是调用它的Student. 这里存在Domain Object与其DAO之间的调用环路了,的确让人很不舒服。其实, 充血模型的这类问题不仅存在于持久化的场景中,任何一个以JAVABEAN为参数的接口都可能会与Domain Object循环调用。 A:这还只是第一个问题。还有第二个问题。 “事务”不方便再以AOP方式来控制了。在贫血模型中,所有业务逻辑都集中在Transaction Script中,我们一般会用XxxService来命名这些事务,然后以AOP的方式在所有名为XxxService.doSth()的操作中强行织入事务。 B:嗯。 Domain Object的名字一般不会遵循某种命名规范,很难确定合适的AOP织入点。

关于Domain Model的对谈录之二: 充血模型中的Service Facade

A: 充血模型中的Service Facade地位会有点尴尬 B: 讲什么东西啊?说清楚点! A: 别急嘛,比如说 在Transaction Script模式下,表现层一般通过 类似于“XXXService” 的Facade来调用业务层的服务,是不是? B: 是啊。不过在充血模型中,已经没有Transaction Script了,也就是说表现层就要直接通过调用Domain Object来获取服务了。 A: 对。 B: 这有什么不好? A: 那还用说吗, 层和层之间的接口应该尽量单一和集中嘛,这样才能体现封装性嘛。 B: 哦,是。不过我们可以仍然保留一些很薄的Transaction Script作为Service Facade,这些Facade自己不实现业务逻辑,而只是给Domain Object做二传手。 A: 是。但 Facade一般怎么做二传呢?基本上都是在复制Domain Object的方法签名!,简直无聊死。 B: 这类Facade不要不行,要了又无聊,怪不得你说它们地位尴尬。

关于Domain Model的对谈录之一: 充血模型与OO

一篇文章只写一个小主题,这样才能让读者集中注意力。 不过此系列文章都是给自己看的,因为它们没什么新意,都是在别人牙慧的基础上总结出来的 =================================================================================== 结论:   充血模型比贫血模型更OO ========================================== A: 充血模型比贫血模型更OO.因为一个领域对象中既有数据又有行为,符合对象的定义 B: 这太牵强了!你还是说点有实际意义的吧。 A: 好吧。比如说,我们可以在充血模型中 通过多态消除IF/ELSE,这算是典型的OO吧。 B: 举个实际的例子吧。 A: 好。比如你还在上大学的时候,天天要去食堂。一般情况下,你还没开口,食堂师傅就给你打好了5毛钱的饭,为什么? B: 因为我是男生。如果是女生,默认打3毛钱的饭。 A: 对。那请你用Transaction Script模式,也就是贫血模型,实现“默认打饭”逻辑。 B: void 打饭(student){ if(student 是 “男生”){ 打五毛; }else{ 打三毛; } } A: 好。看我这个    void 打饭(student){ 打(student.默认饭量()); } class MaleStudent extends Student(){ int 默认饭量(){ return “五毛”; } } class FemaleStudent extends Student(){ …

关于Domain Model的对谈录之一: 充血模型与OO Read More »

Alternatives to LoadRunner

1. [Recommended]Web Application Stress (WAS) Tool( http://webtool.rte.microsoft.com/). 2. Apache JMeter (available at http://jakarta.apache.org/jmeter/index.html) 3.Grinder