SSH是不是从面向对象的退化

这几天在看SSH(Struts+Spring+Hibernate),总觉得这种开发框架不是很符合面向对象的分析与设计。
bojo已经退化成很单纯的一种数据结构struct,用来在三层间进行数据交换,不过是一种数据载体,说它是对象有点勉强;它没有业务操作行为,只有对本身数据的getter与setter。
Service也成了一种API集合,不过是以对象的方式包装的,并利用了对象的多态特性,可以通过IoC被Spring管理。
这基本上分离了行为与数据。
在分析与设计时,完全可以用面向数据流的方法来进行。
SSH中的系统开发,实际是通过Service对单个pojo或者一组pojo中的业务数据进行一系列业务操作来实现。这和我们以前直接通过sql语句操作数据集好象没有什么本质的区别,并且,不通过ORM,直接传送Map/List/Vector这种与关系数据库表结构一一对应的数据结构,效率上要高得多。

SSH是架构平台技术,你文中所说的现象是对SSH这个平台技术不正确的用法,SSH就是高速公路,结果有的人在上面跑拖拉机,明显是误用。

SSH + Evans DDD 才是目前正确的软件开发方向。也就是说,好的框架平台再加上好的分析建模方法才能开发出一个好的软件。

关于数据和行为等观点,也就是贫血模型问题,在本站之前也有讨论,可以查询一下,这个问题主要是因为系统简单时,只有数据和分离的行为,但是业务复杂后,很多会将复杂的业务塞在行为Service里面,这就造成贫血模型,这是错误的。应该丰富模型数据,具体可见JiveJdon3的model包。

在我看来,Spring是一个业务组件容器,Hibernate则提供了一个bojo容器。
但出于面向对象的限制,这些容器中的只能放置拥有同一抽象接口的组件或者bojo。
我觉得对于松耦合意义不是很大,因为如果业务要更改,很多情况下还是得更改接口类,并且在一般性的开发中,不需要一个接口类对应多个业务实现,基本上是一一对应的关系,即一个接口一般只有一个实现,除非系统设计得非常精妙,能把一组业务实现抽象到一个接口中(根据我的经验,由于需求的不确定,这有点自找麻烦,削足适履)。bojo也是同样的。
实际上,我觉得ESB或者象EOS的XML总线更方便组装应用。有点象UNIX中的管道命令;我只需指定操作的目的(如User.AddUser,表示要调用User命名空间中的AddUser业务),至于目的由谁来实现、接口参数、返回值,则由XML文件来定义;虽然会造成业务组件管理的扁平化(没有接口的层级关系),带来不便,但更清晰,更容易理解!在实际中,甚至不用知道这个组件是否实现,只需要有BUS接口就行了,不用象以前那样new一个业务类,也不用要知道接口类,从Spring上下文中get一个。
btw:《Java实用系统开发指南》现在哪里有卖呀?好多网上书店都没有货!

其实,两者不矛盾,前者是后者的基础,不同类型的业务实现有不同的业务接口,当然不会使用同一个接口,接口就是体现了类型的区别,如果一个应用只有一个接口,那么说明程序员没有设计水平。

两者的区别就是解耦程度不一样,后者ESB使用XML解耦,解耦程度高,但是带来问题就是复杂性提高,将本来是业务接口和业务实现的对象设计关系破坏了。

根据不同目的选择不同架构。

“不同类型的业务实现有不同的业务接口,当然不会使用同一个接口”,如果是这样,那在Spring为业务对象定义接口类有什么意义?
我看到有些人在service中写一下addUser(),然后在dao中也同样写一个addUser,在业务类中基本上是直接调用dao中的addUser,这样做应当不是很合适的吧?
是不是应当dao只是实现CRUD操作,而service中调用CRUD来实现业务操作,而不是在service中把一个业务操作当作一个过度,人为薄化service。
例如,我要实现addUser(),应当先R,没有找到则C,找到了则U,这样来做?
我感受到,SSH实际上提倡了行为与数据的分离?除非service是有状态的,但通过Spring注入的业务组件不太可能有状态呀?才学SSH,不是很明白!?

你上一个帖子都是离开具体业务对象进行的一个抽象,有失偏颇,建议看一下Evans DDD,可以解决你的疑问

有了spring和hibernate后,好象设计模式都无法用上了,学了那么多设计模式,但在项目上使用的微乎其微!

像添加用户,添加之前要不要核实一下让不让用这个用户呢?核实和添加是两个功能,添加是极其简单的作业,但是核实就不是,根据什么标准来核实,哪些名称被允许,哪些IP被禁止,可以越来越复杂。单看比较简单的情况下把核实和添加写在一处saveUser(A处)没什么大不了的,但是一旦您的核实动作变得复杂后,再来A处看那些核实逻辑,就明显不符合saveUser这个接口命名了。这应该在addUser接口里有两个动作,一是check,二是save。
可以采用AOP拦截,把核实动作拿出来,但是想知道到底被谁拦截却显得不太明显。
也可以采用规则定义,一个核实接口弄进去,以后不断的实现这个接口,不断的改变核实这个业务。不要的规则我就扔掉,有新的我就继续添加check的实现,不被核实的就抛业务异常(IpCheckException、BadNameCheckException等)。这些实现就能通过spring注入,但是前提是您必须先把这个check接口提炼出来。
如果没有核实这个动作,单单就只是需要添加,那就没什么业务逻辑了,也就用不着什么分层,反正就是一些CRUD,在哪做都行,一个Exception异常就足够用了。

有这种感觉

>有了Spring和Hibernate后,好象设计模式都无法用上了,学了那么多设计模式,但在项目上使用的微乎其微!

有这个感觉的人说明他的面向对象在蜕化,退化到数据库编程了,用SQL实现业务功能,当然就感觉用不上OO了。

用OO和Evans DDD分析设计你的业务,这样设计模式等OO概念才真正派上大用场,这个用场才是设计模式真正用处,SSH这些框架虽然也是设计模式组成,但那时另外一个领域,他们做了,你就不必做了,你就将设计模式用在业务分析设计上。

看下面JiveJdon3抓BUG反应的DDD设计思路问题:

http://www.jdon.com/jivejdon/forum/messageList.shtml?thread=34936&message=23118421#23118421

设计模式是从那些最基本的软件开发原则(比如OCP,LSP,DIP等)发展而来的,只是这些原则在特定情况下的最佳实践。实际情况千变万化,只有基本的原则才是永恒不变的,常用的24种设计模式只是对于原则实践的24个例子。由基本原则发展出来的还有架构模式,他和设计模式其实没有本质上的区别,只是关注的高度不同而已。

SSH,总的来看,在一定程度上实现了组件之间的解耦,也是基本原则的一个出色的实践。不过因为它解决问题的层次更高,所以是架构模式(architectural pattern)。

感觉在SSH中用不上设计模式,正反应了SSH架构的优秀。之所以这么说是因为设计模式的实现,是为了解决特定的问题(大部分是解耦)而写的代码,往往是多余的(就算没有,当前的程序也可以运行的很好),而在SSH中,我们不需要写多余的模式代码,同样可以达到相同的目的。举个例子来说,如果没有Spring的话,我们可能需要自己写很多的Factory来解耦(在没有用Spring以前我就是这么做的)。有了Spring,我们只需要定义接口,写纯业务代码就可以了,解耦的问题容器已经给解决了。

最后贴一段wiki里design pattern的定义:
In software engineering, a design pattern is a general reusable solution to a commonly occurring problem in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Algorithms are not thought of as design patterns, since they solve computational problems rather than design problems.

Not all software patterns are design patterns. Design patterns deal specifically with problems at the level of software design. Other kinds of patterns, such as architectural patterns, describe problems and solutions that have alternative scopes.

SSH考虑是架构上的。面向对象最直接是体现在“领域对象”中,如果你开发的系统都是数据处理方面的CRUD,没有复杂的业务,所以感觉到SSH没有什么,pojo只是一些“哑对象”和dto一样只是数据传输的作用。当遇到业务复杂的系统时,你就会深刻体验到OO的精髓了。OO必须要有设计的思想,光有编码能力是远远不够的。