解耦合设计的一个困惑,请大家讨论

我在设计中遇到一个问题!而且我想或许大家也会有类似的困惑,还是我多想了抑或是孤陋寡闻。具体问题如下,简化了分析模型
利用ctrl(action)接受客户端提交的请求并分配到不同的DS(DOMAIN SERVICE),然后DS调用BO,BO在调用DAO来完成持久化!粗略地看看是没有太大的问题,耦合度也可以控制在一定程度,但是我有个问题出在哪里呢?我觉得BO是比较容易变动的东西,基于将变动与不变分离的原则,我希望可以设计一个这样子功能的bo。利用最简单的工厂模式,首先定义好一个interface在里面定义特定BO的所有行为,然后定义一个abstract class 里面定义BO的所有属性以及get/set方法,当然他继承前面的interface,然后再根据不同功能,根据职责分配的方式,以不同的实做类来实现不同功能(继承前面的abstract class),但是因为对DS来讲的话,我希望降低他与BO的耦合度,在DS来说我希望他只能通过interface访问(利用工厂实现)。表面看好象符合我要求了,也满足了提供内聚性降低耦合度的想法,但事实上大家看,如果我的BO 有三个功能的话那么在interface中必须定义三个行为才能通过接口统一访问,不然对DS来讲提高了耦合度(假如有多个interface的话),那么不考虑abstract class对于每个实做类来讲,并没有达到我想要的结果,为什么,因为内聚性并未提高,他得到了自己不想要的行为(例如实现新增,结果还有修改和查询也随继承得到了),这违背了我的初衷!我目前使用了一种妥协的办法,就是在实现类中对非本类功能行为的实现,全部都是直接抛出异常,但是非常遗憾,这比我理想的情况相差实在太远,因为这样子一来根本就不是一个良好的设计!我一直被这个问题困扰,不知道在坛的高人有没有什么很到的解决方案,或者大家一起来讨论一下此问题,小弟不胜感激!

如果我这样子做是否有设计过度的嫌疑,而且我也在思考是不是最初我的思路就错了!希望大家能多回复啊!小弟一直困惑啊!

sorry,不是非常明白你的意思,可贴些代码或画张图看看。

不要试图在业务层使用工厂模式,因为工厂模式有一个前提约束:统一产品接口;其实这世界丰富多彩,没有那么好统一的,容易造成程序员强迫统一,进而脱离设计本意。

为什么一些回复不见了?

我前面的一个回复不知道在哪里去了,我的意思就是说希望如果我的bo多了一个功能的话,我不需要改代码,只需要在顶层BO(interface)中添加一个方法描述,然后再添加一个实做类就可以了,但是外面统一用顶层接口来调用!

不知你抽象AbstractSalesBO有什么目的?是因为考虑BO需要变化,然后
基于将变动与不变分离的原则进行分离,考虑思维正确,实现方式有些问题,其实如果比较熟悉GoF设计模式,我们已经知道一个很好的解决方式:桥模式。

目前我们都是采取Domain Model/Domain Service方式来实现桥模式,Service中的一些操作行为和Model中的set/get属性分离,后者可能等同于你的abstract class东东。

另外,DS向客户端Open展示时,最好不要通过你图中的SalesBoFFactory实现,而是使用Ioc模式/Ioc容器,通过Ioc,就没有Facade Factory/Manager之类的缺点。

banq老师你说的很对,目前我想到的也是桥模式,因为我也发现了自己设计上的缺陷正在改进中:),但是我有个疑惑在这里,我的想法是这样子的:
我定义AbstractBO的目的是为了,将set/get和属性值与具体的实现某一功能的比如insert功能等的实现类分离,每当DS中增加一个功能比如多一个查询功能,那么我就想直接再加一个实现了查询的实做类,与此AbstractBO组合起来达到自己的目的,而不需要修改现存的某个类,以后如果是多了某个属性那么我只需要修改AbstractBO,而不需要修改现在的实现类,这样子达到我的设计目的,但是我目前并没有得到一个很好的方法来实现他,所有希望banq老师能再指点我一下!谢谢

>我定义AbstractBO的目的是为了,将set/get和属性值与具体的实现某一功能的比如insert功能等的实现类分离

据现在理解,这个AbstractBO就是Domain Model啊,下面是一个典型的Model Model:


public class Message{
private String messageId;

public void setMessageId(String messageId){
this.messageId = messageId;
}

public String getMessageId(){
return this.messageId;
}

}

不知你的AbstractBO到底是不是这样,你可以举个例子,将AbstractBO其中字段show出来看看。

正是如此,但是我并不认为他是domain modle ,他的作用是负责在domain与dao层之间传输(或者可能会附加一点与dao层有关的方法,但是我这里没有加),所有我在这里定义一个AbstractBO,因为BO将会与DAO打交道,如果每次变更都要变更BO类,岂不是很麻烦,所以我就想到了这个法子,但是可能有些问题,因为接下来的步骤我自己都觉得很乱!接下来我是这么想的,这个BO在被DS层调用的时候,我只给他一个统一的BOInterface,而且这个接口中定义了DS层所需要的全部方法,但是这些方法我不想利用一个类来实现,这样子,那个实现类的内聚性太低,而且一但有所变化,可能会牵连很大,所有我想是每个可被DS层调用的方法就用一个类来实现,这样子有多少个功能就有多少个实现类,但是他们都只有一个统一的接口来被调用,同时这些实现类也extends 我的AbstractBO如果domain modle 有任何变化我也不需要去修改每个实现类,只需要修改这个AbstractBO 就可以了,但是我在使用adpter或者bridge的时候怎么都觉得不好,所以脑子比较乱了,希望BANQ老师能指点一二,谢谢你耐心的回复!

因为DS需要的不只一个方法(比如insert,update),所以用IOC也比较不可能,我也不想定义一大堆的interface啊

>但是我并不认为他是domain modle ,他的作用是负责在domain与dao层之间传输,所有我在这里定义一个AbstractBO

你的根子问题就出在这里,这是一个Domain Model,作为你个人来说,你可能缺乏业务建模相关经验,持久层是Model的持久。

在目前理论界存在一个鸿沟,各个流派众多,尤其在Model统一上没有一致认识。

Model是业务Model,是从业务需求分析中得来的,你可参考前段时间本站首页关于四色图等业务建模方法。

Business Object(BO)是以前的概念,表示业务对象,实际和Domain Model是一致的,都是表达业务模型的,而现在Ruby on Rails/JF等域驱动框架如此流行的情况下,Domain Model已经占据Java系统的主流,你可以打开Spring/JF等很多开源软件(最近版本),他们都放弃了BO而使用Domain Model来表达业务对象。

BO大概是EJB刚刚诞生时,在J2EE模式中定义,其实,SUN的J2EE核心模式已经有很多已经不用或被相似概念替代,例如VO/DTO等。

将Domain Model作为DTO传入持久层持久,这是一个简捷直接方式,如果你专门做一个DTO,将增加系统的复杂性,就象你现在碰到这样的问题一样,焦头烂额,而且业务对象是随着业务变化经常修改,一旦修改,你还要更改DTO等各个层,问题就大了,J2EE多层结构带来了异常复杂,这在本站以前专门讨论过了。

看下图,左边就是各种DTO以后,导致系统混乱,难于维护,而右图采取以Model为主要线索,穿越各层,这样清晰便于维护:

在Spring 2.0框架中,已经提供Model的CRUD等DAO操作直接在Model中实现,也就是说在业务对象中,不但是set/get,而其有自己的持久化,从这里看出,夹在Model和DAO之间的DTO更加没有必要,无疑是多余,增加复杂性,DTO从某种角度说,是以前EJB实体Bean没有采取IOC模式导致的模式。


banq老师首先感谢你的回复,你所提到的相关文章我也是看过的,我目前只所以会这样子是因为项目的大框架是利用BO来做的,所以我必须如此来设计。而我目前要解决的也不是各层之间的传输问题,这不是我向你请教的重点,因为在项目的大框架下面我是不可能做如此大的变动。我现在的主要问题是想做一个这样子的BO(因为项目必须用BO这种框架),在DS调用BO的时候,我不需要在一个类里面实现所有的功能,我要提高内聚性,降低耦合度,就是把各个功能的实现分到不同的类,但是DS在调用的时候完全不会感觉到这种差异,他永远只能通过interface来操作,这就是我想要的面向接口编程,比如我没新增一个功能(原来只有查询我现在要多一个新增),那么我只需要在接口里面添加这个行为,然后在实现包里面添加一个相应的实现类就可以了,这样子我觉得内聚性和耦合度都会朝我的要求的方向发展,不知道我这此描述清楚没?还是在次希望banq老师能继续给我一些建议!谢谢!

sir banq!!where are you?help!!

看看spring吧,它会给你一些启迪.利有ioc实现类之间的基于接口的松藕合.

关键还是不能将CRUD行为分开,单独变成类,什么东东可以变成对象?你的对象粒度太细,可以说是一个方法一个对象,有些过度设计了吧?