论坛首页 综合技术论坛

[讨论]实际case中,有两种设计方案(附图和解说),请大家来...

浏览 14198 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2004-06-13  
一、需求:
一个企业黄页系统,每个企业根据自身特点会属于不同的目录下,一个企业也会属于多个目录。
企业会有广告、产品等附加信息,每种附加信息都可能有多条,比如10个广告,3个产品等
目录系统要求做到通用,也就是说,以后可能会有新的应用,目录中管理的可能不再是企业,也许是别的什么东西。

二、设计:
A方案

方案特点
1、将目录与目录中管理的具体信息(如company)隔离开,使用了一个entry类,实际上目录里的东西是entry,而entry会去获取实际的信息(如Company)
在黄页应用中就新增YPDirectory类和YPEntry类,来把黄页中的元素(Company)和directory、entry连接起来。
2、company类负责维护Manufacture(中文意思是产品,这个英文用的有些不妥,product更适合,但实际的图是这样,我就没有改了)和Advertisement列表

B方案

方案特点
1、company类实现了IItem接口,通过getItem()方法将自身返回给调用的类,调用者通过调用Entry.item.getItem()获得一个Object类型的对象,然后根据需要,转型成正确的类型(如Company)。以后有新的应用也需要使用这个目录结构,只需要实现IItem接口即可
2、管理扩展信息列表的类都从ExtendsManager继承,而且具有一个user属性,类型为CardUser(Company为CardUser的子类),从ExtendsManager继承出ADManager(广告管理)、ProductManager(产品管理),以后也许会增加一个CustomerManager(顾客管理),这样就把扩展信息管理的指责从Company类剥离出来,Company类无需知道有哪些扩展信息要管理,而ExtendsManager的子类知道自己要管理谁的信息,管理什么信息,即使增加一种Manager,Company类也无需变化。

谢谢!
   发表时间:2004-06-15  
题目的重点有两个:
1.目录中管理的可能不再是企业,也许是别的什么东西...
2.一个企业也会属于多个目录...

于是:
1.只要目录与目录内容分离,即可保证目录能扩展来管理其它类型的东西.(倾向于A)
2.只要目录能够记录多棵树, 且树结构的节点与组成节点的目录内容分离,即可保证'企业'作为节点被多棵树重用.

俺的拙见简要描述如下:

[/img]
0 请登录后投票
   发表时间:2004-06-16  
看得有点昏.
对UML图有点想法:
1, 没有附详细解说的UML图, 让人迷惑,使交流更困难.
2, 一大堆的set/get方法, 扰乱了UML图要表达的设计意图.

打个记号,有空再研究.
顶楼的A方案图画得不错,不是用ROSE吧,是什么软件?
0 请登录后投票
   发表时间:2004-06-16  
引用
一、需求:
一个企业黄页系统,每个企业根据自身特点会属于不同的目录下,一个企业也会属于多个目录。
企业会有广告、产品等附加信息,每种附加信息都可能有多条,比如10个广告,3个产品等
目录系统要求做到通用,也就是说,以后可能会有新的应用,目录中管理的可能不再是企业,也许是别的什么东西。


看了一下,楼上的设计,感觉有点乱,而且你的系统设计不需要这么复杂。

第一步:需求分析。
需求楼上基本上说清楚了,就是目录这个概念有点模糊,应该不是windows里面的那种目录吧。我参考了一下网易的黄页:http://114.163.com/,对目录的概念理解如下:一种分类的方式。比如目录可能是某个行业,某个地区。。。。(不知我的理解是否对)。

第二步。建模分析。
在这里面企业这类数据对象是主对象,目录应该仅是其一个属性。由于主对象可能在以后会扩展,不限于企业,所以应该将其抽象成一个接口。
基于以上分析,这里面应该有如下的数据对象:
----------------------数据模型层面的----------------------------------
主类:企业类、学校类。。。。。继承接口IEntry
附属类:目录类(地区、行业。。。。。),产品信息类,广告信息类。
主类与附属类的关系:一对一,如地区。一对多,如广告信息(这时主类方法可以返回java.util.List集合来包装多条广告信息)
-----------------------功能操作层面的---------------------------------
工具类:提供通用的对数据对象的操作,如insert,delete及一些查询等等,以数据对象的接口为参数和返回类型,可以不用关注其具体实现类。
各种功能模块:这就要看你具体的功能要求了。

在这里我不赞成将操作做数据类里,如:
class School(){
   .....
   .....
   .....
   public void insert(){....}
   public void remove(){.....}
   public List getSchools(){.....}
}
这样混在一起不太好,我认为应该保持数据类的单纯性,它就相当于一个类到数据库的字段一一映射(类似于EJB中的实体类)。而且从习惯思维上:人不能自已将自己提起来。同样的习惯思维:数据类不能自己将自己删除、插入、取得(当然实现是可以实现的,但有点不伦不类---仅为个人感觉)


UML类图如附件:(用ROSE画的,很丑)
0 请登录后投票
   发表时间:2004-06-16  
z_bus:你的图我有些看不明白,那些圆圈是什么意思?可否解释一下?

glchengang:你设计的IEntry接口,和我的帖子里方案B的意图是差不多的,我觉得你的设计更简练一些,比我的好,不过还应该给IEntry增加一个directory的属性。至于把delet等操作放在一个单独的工具类里,那个工具类势必是一个全局的类,或者其中的方法都是static方法,我觉得有些违背oo的原则。

我还有个疑问,方案A是平面的类层次,没有接口,没有继承,而是使用一个关联类来解决两个类的关系的问题。方案B以及glchengang的设计,使用接口作为解决方案。究竟是平面的类层次好?还是有接口的类层次好?我个人的思维方式是倾向使用接口的,但我也有些担心接口维护的问题,比如一旦接口需要增加一个方法,那么所有实现这个接口的类都要修改。
0 请登录后投票
   发表时间:2004-06-16  
darzui:
1."圆圈"表示实体类,是Rose中类的一种版型(entity).类的属性和方法没有显示出来,是希望重点关注核心实体间的关系.

2. 俺也觉得A方案显得比较复杂.

glchengang:
引用
我认为应该保持数据类的单纯性,它就相当于一个类到数据库的字段一一映射(类似于EJB中的实体类)。而且从习惯思维上:人不能自已将自己提起来。同样的习惯思维:数据类不能自己将自己删除、插入、取得(当然实现是可以实现的,但有点不伦不类---仅为个人感觉)


俺有不同看法:
1.对于某个实体对象来说,它自己的属性,其操作和读取的细节.您认为还有其它对象比它自己更熟悉吗?理所当然应该由它自己来提供!至于重用性应该从应用框架层来提供抽象,仅仅利用工具类是很难协调共性和个性的矛盾!

2.除非某个功能很复杂,需要多个实体类协作才能完成,可以考虑引入一个控制类来提供! 引入一个实体,也是您在向系统申请资源.应用服务器的资源是有限的!

个人看法,见笑了...^@^
0 请登录后投票
   发表时间:2004-06-17  
我支持方案A。楼主你这就是个简单的CMS系统。可以参考JSR170的结构。和你的方案A雷同。

我本来也是支持把crud都写到外面来,前段时间开始支持由DomainObject自己负责SaveUpdate和Delete
而由外部类负责Retrive。

同意z_bus说的,对于某个实体对象来说,它自己的属性,其操作和读取的细节.没其它对象比它自己更熟悉。

从OO的角度来看,combine data and behavior 这是OO的最初意图。 而现在常常一个Object只有Data而没有Behavior了。

如果PersistentManager.save(AObject obj),那么这个object和C中的struct又有什么区别。都只是一个DTO而已。那不如光暴露public的data field而不写get,set
0 请登录后投票
   发表时间:2004-06-17  
引用
至于把delet等操作放在一个单独的工具类里,那个工具类势必是一个全局的类,或者其中的方法都是static方法,我觉得有些违背oo的原则

如果此方法没使用公有状态变量,写成static方法还是不错的. 在JDK里就有很多static.

引用
但我也有些担心接口维护的问题

确实,而且加东西进接口容易, 要去掉它就难了, 所以接口一定要抽象好.

引用
1.对于某个实体对象来说,它自己的属性,其操作和读取的细节.您认为还有其它对象比它自己更熟悉吗?理所当然应该由它自己来提供!至于重用性应该从应用框架层来提供抽象,仅仅利用工具类是很难协调共性和个性的矛盾!


一般意义来说,你的话是并没错的,但这个类比较特别---实体类. 保证一个纯数据类 是有好处的,它让你数据层很清析。在EJB中的实体类还有Hibernate参考文档中的好多例子,都是采用这种方法。 我们不妨来深入分析一下,为什么将insert等操作放到实体类中不合适。
  首先放在数据类中和拿到数据类外从技术上来说都是可行的。但在实体类中加操作方法会使得这个类变得臃肿,还有如果我们需要一个查询方法,这个方法能根据某个字段的值得到数据对象(如ID值),如果写在类中会是这样。
Class School(){
      Long id;
      String Name;
     
     public void insert(){....}
     public void delete(){.....}
     public School getSchool(Long id){.......}
}

 要调用这个方法getSchool我们还得new School, 那写成静态方法?也不好。总之这时你发现getSchool(Long id)放在School类中一点都不合适,因为它从概念上来说根本就不应该是一个School的方法。这样的方法还有
public List getSchools(){....}  //得到所有库中的School记录
public void delete(Long id){....} //根据ID删除School记录
public void delete(School obj){....} //根据转入对象删School记录
  当然也许你说那就将这类方法拿出去,但将insert(),delete()保留在实体类中。可以我们反过来一想,既然要拿一部份操作类出去,不如都拿出去,好集中管理。
  也许以上的理由还是不够充分。我是写这种实体类时,都是将操作方法拿到外面的,在实践中没发现有什么问题。不过将这方法放到里面会怎么样,关键是在编程是否感觉到了混乱和模糊呢?我没试过这个方式,所以难下结论,希望大家继续讨论。

引用
如果PersistentManager.save(AObject obj),那么这个object和C中的struct又有什么区别。都只是一个DTO而已。那不如光暴露public的data field而不写get,set


关于这个问题,在<<Effctive JAVA>>中有详细描述。我在最近的<程序员>杂志中看到一篇C++之父的访谈,他很讨厌和饥讽这种大量的set/get的做法。不过我觉得这仅是使用习惯和统一代码风格的问题,现在的JAVA IDE,已可以很方便生成set/get方法。  

引用
我本来也是支持把crud都写到外面来,前段时间开始支持由DomainObject自己负责SaveUpdate和Delete
而由外部类负责Retrive。

可以说说为什么这么转变吗?
0 请登录后投票
   发表时间:2004-06-17  
还有两点:
1、如果你的系统要能同时支持多种数据库,你会后悔将操作写在实体类中。
2、如果你用hibernate做持久层,而且你的实体类有继承关系,你会发现把操作从实体类中抽取出来会让你少写很多重复的insert(),update(),delete()等方法的代码。
0 请登录后投票
   发表时间:2004-06-17  
再谈谈俺的观点:
引用
如果你的系统要能同时支持多种数据库,你会后悔将操作写在实体类中。


俺认为:
1.支持多数据库与操作是否放在实体类中是两回事情,不可混为一谈.

2.单就支持多数据库来说,不外有两种方式:
(i) 最直接的:系统需要支持多少种DB就提供几套针对不同DB的SQL,这样可以
   充分利用各个DB的优化措施,但是一般规模的公司能够供养多少能精通多种DB差异写法的programmer呢? 即使有,其编码量和维护成本都是不可想象的.俺的公司曾经想以这种方式来支持SQL server and oracle 但是失败了.

(ii)求同屏异:自己提供SQL翻译引擎,简单说就是在 programmer 和 DB间引入一个中间层;让多DB对programmer来说是透明的,他们只需要写一套程序.而实际上两方式应该同时提供;

大部分的工作都能够按(ii)的方式来完成,只有少数对性能要求极其严苛的情况才会使用(i)!这样才能既兼顾效率,又保证性能.
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics