怪怪 | Nothing, Everything

"有过一个发疯的时刻,有感觉的钢琴以为它是世界上仅有的一架钢琴,宇宙的全部和谐都发生在它身上." - 狄德罗
随笔 - 109, 文章 - 3, 评论 - 2072, 引用 - 60
数据加载中……

怪怪设计论闲谈篇:职责与解耦的矛盾

正式讨论之前,先看看这两个问题:当我们的对象所涉及的操作不断增加时,我们是否应该:Book.Save,Book.Serialize, Book.Method1,Book.Method2这样一直增加下去?或者在某个垂直的逻辑中增加其它逻辑时,不断的扩充Book.Save,要么象有的朋友说的那样分离 出去,再回调?但是Book.Save有理又有在,无论数据->对象,还是对象->数据,考虑到数据和对象经常一起变化,恢复对象的状态这部分确实应该留在对象内部,同时,我也认可这本来就是对象的职责。

为了大家所谓的“低耦高聚”的目标,也为了保持职责的合理性,希望大家考虑一下,当Book没有Save时,我们除了属性赋值是不是就无路可走了?这就得那些没包含在这次讨论中的习惯性做法(比如平时对.NET Framework和ADO.NET的使用方式)包含近来,看看很多同志指出的美女走光问题,除了给美女一个电棍让美女负担起警察打击偷窥者的职责,能不能通过换件裙子来解决。

我们平时用惯了IDataReader给对象赋值,所以很多人说的那种,从外部通过属性赋值的情况就广泛存在,比如CommunityServer。如果换一个方式呢? 把IDataReader直接交给Book, 然后Book自己展开数据是不是好很多呢?于是有人又说了,这跟IDataReader耦合了,不利于移植等等。或者我根本没用ADO,所以没IDataReader。后者可以通过给自己的数据操作层实现IDataReader搞定; 关键是前者,前者的非法性还表现在,把ADO的接口带入了逻辑层;等等等等, 反正很多。那么为什么不能自己做一些类似IDataReader的接口, 然后把ADO.NET包含的概念作为变化封装出去呢? 

在保存数据的时候也一样,不是把数据全部读出来去保存,而是让Book准备好需要保存的数据,总而言之归它管的一分不落,然后实现或者返回出一个统一的接口里面全都是要持久的数据。至于如何跑回书架上,或者被贼给偷跑了,那是别人的事。 毕竟某兄弟回复说的,今天加个Cache明天加个Log后天加个Permission最后数据库都不用了的情况也确实有。这些都该Book负责吗? 不是说只添加不修改吗? 难道非得要求必须AOP? 我是Anders的忠实Fans,我不认为AOP解决了什么本质问题。怎么又说回职责问题了,总而言之,现在总不能有人说美女走光了吧。 

其实我们所说的方法,往往都有学习的对象,大家可以想想各种Control对于ViewState的使用, 它其实就是这么一个玩意(关于Control如何使用和持久化ViewState的文章,园子里就有)。那么我们也可以这样,数据就是数据,要什么属性,而且IDataReader出来的不就是一砣类似字典的东西吗?正好直接拿字符串和我们自己定义BL层与数据层之间对接的接口对应(与IDataReader不同的是,我们定义的接口是在逻辑层中使用的,除了象一个数据集,不包含任何和数据层相关的内容),觉得不过瘾,把对应关系保存到配置文件里去。无论如何,希望让对象自己负责恢复状态,同时又不希望对象负责存取逻辑的矛盾,并非无法解决,ViewState的方式只是其中一种解决方法。

我们不妨再看看.NET Framework如何让Serializer和你的对象在没有联系的情况下,通过增加一个翟通道,即不介入对象内部逻辑,又负担了对象持久的:首先实现ISerializer这一接口,同时实现固定方法签名的构造函数。保存数据时,他让你自己打包然后从你的接口实现中获得数据对象,恢复对象时,他调用你那个特别的构造函数,把数据字典还给你,然后让你自己填充。拿Book来说,如果增加了需求,难道非得让Book自己重新实现一个Book.Serialize方法吗?鉴于一些朋友可能不清楚Serializer的工作机制,我借用一下MSDN的简单例子,同时有所改动:


[Serializable]
public class MyObject : ISerializable 
{
    
public int N1 { getprivate set;} //公开取,私有存
    public int N2 { getinternal set;} //公开读,内部存
    public String Str { getset;} //这些是VS 2008支持的写法,不用自己定义私有变量了

    
public MyObject()
    {
    }

    
protected MyObject(SerializationInfo info, StreamingContext context) 
    {
        
//这个特殊的构造函数会被自动调用,如果是我们自己实现,就某Manager调用
        
//其实如果没有复杂的构造函数初始化逻辑,比如给readonly变量赋值
        
//可以将SetObjectData直接实现于接口,由我们负责数据存取的部分来调用
        SetObjectData(info);
    }

    
protected virtual void SetObjectData(SerializationInfo info)
    {
        N1
= info.GetInt32("i");  //由对象自己将数据字典展开
        N2 = info.GetInt32("j");  //还原对象状态
        Str = info.GetString("k"); //这样就可以把跟对象无关的存储逻辑外包出去
    }

    [SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter
=true)]
    
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue(
"i", N1);//info可以理解为Serializer定义的数据字典格式
        info.AddValue("j", N2);//这相当于持久化的概念进入了BL层
        info.AddValue("k", Str);//所以当我们实现时,应该根据业务逻辑定义自己的数据字典
    }
}

Serializer:
BinaryFormatter formatter 
= new BinaryFormatter();

保存至fs:
formatter.Serialize(fs, a1);

从fs读取:
formatter.Deserialize(fs);

在上面的上下文中,作为Serializer的BinaryFormatter,相当于BookManager这样的角色(也仅在该上下文中,它们的作用有所重叠,因为BookManager不应负责对对象持久的具体实现),但是它更通用,且与任何对象没有耦合关系,毕竟,这样的方法不存在在咱们自己定义的对象上。实际上,由于不需要变成二进制流,我们平时的保存和读取的实现要比Serializer之类简单一些(而且一般来说严格停留在数据层中);同时由于我们的对象和数据往往有着一定的联系,这样我们的实际实现,就可以增加一些由业务层定义的数据字典作接口发挥类似SerializationInfo的作用,依靠于合理的设计,我们的接口一方面把BL层和数据层隔绝开来,另一方面强调业务层的需求的同时根据业务需要特殊化。

不过有人可能要说了,你也类似于ORM,我也不管我这是不是ORM,至少自己实现的灵活性,要比使用现成的ORM高,Book内部如何展开数据,既可以写个通用的,在有必要的地方也可以自己搞;效率想优化一下,也不用看/改别人的代码,有啥不好呢?关键是这样的方式,无论亚历山大同志是我老板还是反对派是我老板,挨骂也能少两句不是。:)

估计大家也看出来了,以上方法对于复杂性不高的项目,完全可以取消BookManager,将数据存取职能归并到一个集中的数据管理器中去(不是指数据层内的那种)。这样我们又有只有一个孤零零的Book玩Solo了。那么产生其它按职责来说不应该由Book来负担,但又具有一定逻辑的操作怎么办?比如Log,做一个Log管理器,Book继承下去实现Log管理器需要的接口,LoggableBook仅返回Log需要的东西。怕产生一个LoggableCachablePermitableBook?Decorator就是干这个地... 不是强类型的?范型来了... 还有什么是可以变化的?比如到底套几个Decorator,写个Factory什么来直接返回套好的Book的..。需要注意,如果这些Log/Permission/Cache,都是对数据存取而不是针对Book的,那么Decorator也好Factory也好,针对的目标就不再是Book,而是BookManager或者数据管理器了。

如果有BookManager而不是集中对象存取逻辑和职责,那么数据来源和原来的做法没有变化;但非数据层的数据管理器怎么知道Book的数据来自于哪儿呢?虽然我们可以通过Provider和配置文件指定类与数据层跑腿的之间的对应关系,但答案也可以是"不知道"。比如,数据管理器.Get(Query q),然后BookQuery去继承Query就好了。这个Query及其子类是用来表示查询逻辑的,而并非是用来拼SQL字串或直接数据存储的那种Query,最终通过BL层到数据层的接口与数据层对接。数据层根据它所提供的信息,自己决定如何动作,最后返回BL层所用的数据集接口。这样我们就可以防止数据层的概念侵入到BL层中去。

这种方式的BookManager(或没有BookManager)与原来的方式区别在哪儿,让它至少想象起来还挺顺风顺水呢?关键在于,BookManager和Book不再像亚历山大同志批评的那样,全方位互操作,它们的接触从一个面变成了一个甚至完全可以消除任何特殊性点,只包含BookManager职责所涉及到的数据部分,至于数据从哪儿来打哪儿去,这不关别人的事。反过来对于Book呢,他的职责除了执行其他当仁不让的业务逻辑,也保留了应该由他自己负责的如何展开和打包数据等天赋人权,从而将数据到对象状态的转化工作,封装在了对象自身内部

这种方式与Book.Save区别又在哪里呢?很明显的是Book不再包括它不应关心的逻辑;这样就实现了BookManager(或数据管理器以及各种Query子类)的单独替换和伸缩;在把他们分散到不同的包里时,这样的好处是不言而喻的。另外,相对于Book.Method1/Method2/Method3...这样随着需求变化增加下去,Book同时也保证了一定稳定性。实现这些,是通过对Book增加了一个面对外部世界的点做到的,它本质上更倾向于亚历山大同志说的高聚低耦方式(虽然表现形式不同甚至截然相反),却将存取逻辑通过这个点,转移到了外部

在我看来,以上手段折射到设计和编码的最终产物,其表现形式就是类的大小和数量。密密麻麻的小类我个人也不习惯很难做到,但我仍然觉得,哪怕一个类只有50行,我觉得只要有一点点理由应该这么做那就相当于说必须去做(虚心接受,坚决不改)。在这点上我有点认同Javaeye上前几年鼓吹什么组合子编程的那家伙,只实现很多很多的基础组合子。问题是拆的太散,最后类之间的逻辑对一般人的脑力和项目的成本承受能力就形成了考验。但是没条件实现不是说不应该这么实现:非常多的细棍一齐直冲云霄,只不过有些棍因为需要借助其它棍的支撑力不得不绑上跟绳子,但却尽量保持不接触,防止实际上变成了一根大粗棍。

关于贫血是不是一定就不合理,Book没有Save是不是就一定贫血这两个问题,我有几点看法如下:

1. 如果真的坚持正确的职责,那么该贫血的模型必须贫血;如果充上别人的血,对于其他对象来说这个对象倒是高聚低耦了,但估计如果你不是AOP迷,这个对象本 身就难免成为胶水对象,比如你可以考虑把CommunityServer的Threads类的职责放到Thread类上去是个什么景象。

2. 若Book和BookManager都足够小,那么这种划分不会增加耦合;相反即使是相互操作,只要接口不变,反而将Book本身可能存在的职责和存取职责之间的耦合度降低了。这是CommunityServer和很多人的做法,但是这个做法的种种缺点也确实存在。

我重新编辑了本文把以上观点单独放在另外一个Post中了,见《贫血或职责的讨论》。本文目前只讨论一种不把持久放在Book中,同时又把恢复对象状态保留,封装于Book中的一种做法。关于1,本文中,我们已经把恢复对象状态的逻辑重新还给了对象,不知道Book是否还是完全的贫血?

最后总结一下本文:

3. 密密麻麻的小类,是各种大嘴/大师们都推荐的做法,尤其是如果存在BookManager,那么BookManager的职责到底有哪些需要谨慎一些,否则比起只有Book的做法,就有可能真的增加了耦合。

4. 考虑到Book状态和装载可能分别变化,我们应该拿出一种它们解耦的方法,让Book自己负责数据的展开和打包,同时由其它对象负责数据的存取(对于图书管理员来说让它拿出来和放回去的这个东西已经可以忽略书本的特性了)。本文提出了一种其实大家都见过,且也许能行的办法。

5. 关键问题是,要点接触不要面接触要接触不要不接触,不接触最后的结果,不是AOP(是不是一颗加林仙人的仙豆,暂时持保留态度),就是成了一个巨型的胶水类。当你解决胶水问题时,还是要使用以上的手段,只不过对象凭空多出了几个方法而已。

最后说点题外话:我在想,其实问题的讨论点如果变一变,就会有建设性。怎么变呢?比如大家群策群力,总结一下现实世界里的例子,哪些可以容忍贫血,哪些贫血的代价在未来会很大;这样久而久之就会形成一个指南,为后人也为咱们自己铺路。比如显然亚历山大同志老兄,吃过充血(哪怕是过度充血)的甜头,那么就把你吃甜头的例子拿出来分析,于是大家知道了,哦,当现实事物有这样这样的特征时,充血有好处。比如反对派吃了充血过度的苦头,也把苦头拿出来晒晒,那样大家就知道,这种情况下得小心不要充血充出问题。每个人都这么做了,逐渐的就可以通过统计得出一些较为有效的分类方式和在不同分类下的大致设计方法。

但是如果是目前的方式呢?你说你的,我说我的,把自己在现实中获得经验往一个共同的例子上套,可大家都没有考虑自己已经因为过往的经验有了成见。每个开发者的经验都是不同的(也正是因为经验不同所以站位的角度不一样),怎样通过网络让每个人都或多或少得到他人的经验在我看来是网络比较重要的作用。

而不加限定的就某一个问题,非要得出大一统的结论,在我看来不但不是网络的优势和对我们的帮助,而且根本没有那个可能。

posted on 2007-09-23 11:27 怪怪 阅读(3857) 评论(29)  编辑 收藏

评论

#1楼    回复  引用  查看    

其实不存在通天棍的说法,BL层的类主要起到一个组织者的作用,而行为的最初发起者肯定是界面,而最后跑腿去做事情的多半是数据层的,至于很多对非数据库不可咬到不放的提出诸如要CVS,要FlatFile的,同样的在BL和Data之间的解藕过程就是漂亮的实现你们需求的方法。很多模式都可以用来解决这些问题。

至于Book还是BookManager,其实要看BookManager在那个层,如果BookManager算在BL里面却拿起了ADO.NET去读Book的属性,然后去Insert数据库,打死我都不会承认这么丑陋的方法是好的。
2007-09-23 12:26 | 亚历山大同志      

#2楼 [楼主]   回复  引用  查看    

@亚历山大同志
嗯所以我觉得讨论的时候还要加上一些共识...,我觉得好像没人直接提到BookManager干的是"ADO.NET去读Book的属性" 吧,如果这样,Book再简单点,表模块算了,再加个数据检查和些业务逻辑的类。

你要这么理解那些你的反对派的意思的,肯定蹿火....

至于仅仅是数据库层的替换,我看CommunityServer的做法已经足够了....
2007-09-23 12:35 | 怪怪      

#3楼    回复  引用  查看    

去医院了,昨天晚上说了封装和耦合,回来说解耦的问题。公司体检结果小三高,赶紧去复查了。
2007-09-23 12:37 | 亚历山大同志      

#4楼    回复  引用  查看    

好长的文章呀,佩服,能写这么多。佩服佩服!

@ 亚历山大同志
而最后跑腿去做事情的多半是数据层的

对这句话很不理解,为什么让数据层去跑腿呀?难道是为了更换数据库?
跑腿的应该是逻辑层,而现在的逻辑层仅仅是调用数据层里的一个或几个函数。

如果是这样的话,
那么我感觉 逻辑层就是领导了,数据层是员工。领导一句话,员工跑断腿。
领导安排任务,员工实现(完成)任务。

但是总感觉这样不对劲。



2007-09-23 12:37 | 金色海洋(jyk)      

#5楼    回复  引用  查看    

如果BookManager是BL层,没有用ADO.NET去操作数据库,而是通过数据层接口去操作数据库,用它来封装Book的行为的话,那Book做什么呢?Book的行为呢?没有行为的人是死人,没有行为的类就是死类。如果非要说书是个死物又不能说又不能动。那么见仁见智了,我还是赶紧去医院检查来的要紧
2007-09-23 12:42 | 亚历山大同志      

#6楼    回复  引用  查看    

@金色海洋(jyk)
一个比喻而已,不用过分较真。按照一个说法,劳心者治人,劳力者治于人。BL层的类作为业务逻辑的主要组织者确实就是领导了。所以BL的设计好不好,也决定了Data好不好办事。
换过来说,先有Data的话,员工办事不力,领导也很无奈啊
2007-09-23 12:48 | 亚历山大同志      

#7楼 [楼主]   回复  引用  查看    

@亚历山大同志
嗯,这个问题文章中已经写明,不过我还在编辑,说的越多,需要严格话的地方就越多。

比如:
比如还有如何翻页,如何索引至某一段内容等逻辑

数据到对象状态的转换。

看我Serializer那个例子,你的类比如People因为Serialize不在自己身上,变成了一个死物了吗? 所以我说死物不死物,是天生决定的..
2007-09-23 12:56 | 怪怪      

#8楼 [楼主]   回复  引用  查看    

@金色海洋(jyk)
长没用啊, 还是看到底有没有用.

我这篇文章, 和国外尤其是微软拿出来的很多Practice所表达的概念相比, 最大的不同是, 不再让数据层或某某Mananger去恢复对象状态, 比如PetShop当中那一堆Info的属性等, 而是让逻辑层的对象自身去负责数据的解析, 这样对象和数据就更干净的分离了.

这样逻辑层只用说给我哪些数据, 而不是说给我什么什么样的数据, 由于把数据的表达方式统一了, 逻辑层可以毫无障碍的自己负责剩下的工作. 这样就减轻了数据层的负担, 同时加强了BL层的职责, 减少了逻辑层变化对数据层的影响.

当然这只是一种方法, 肯定还有更好的办法, 不过遇到具体问题才能看到.

关于你说的数据让逻辑层跑腿, 我不太认同, 因为在我看来, 是用户输入让逻辑层动, 然后逻辑层才能让数据层动, 再简单的也是这样啊.
2007-09-23 13:31 | 怪怪      

#9楼    回复  引用  查看    

@亚历山大同志
不是较真,而是说一下我的想法。
在我的设计(还是叫做代码吧,参考第一步抽象)里,代码都集中在“逻辑层”里了,UI层绘制控件,数据层就是SqlHelp + ADO.net + 数据库。
这样才是两头轻,中间重。逻辑层才能体现出重要性,否者的话直接在UI里面调用数据层就可以了,就几行代码写在哪里不是一样?


ps:不好意思,不知道在这里讨论这个,和博主的意思有没有冲突。


=====================

2007-09-23 13:31 | 金色海洋(jyk)      

#10楼 [楼主]   回复  引用  查看    

@金色海洋(jyk)
没啥冲突..., 我只是觉得你的表述要能在清楚点, 大家就好理解了. 而且你说的这个(如果我没理解错的话), 和我最近在琢磨的另外一种设计方式, 可能还有点关系 :).

@亚历山大同志
"去医院了,昨天晚上说了封装和耦合,回来说解耦的问题。公司体检结果小三高,赶紧去复查了。 "

靠这句话我没看见,Good Luck :)
2007-09-23 13:42 | 怪怪      

#11楼    回复  引用  查看    

结果去晚了,挂不到号了......
2007-09-23 15:37 | 亚历山大同志      

#12楼    回复  引用    

@怪怪
能不能写了demo?看看好处到底在哪
2007-09-23 15:44 | anikin2008 [未注册用户]

#13楼    回复  引用  查看    

@怪怪
说句实在话,我真佩服您能写这么长的文章,那叫一个牛字。
虽然我也比较会说,说出来的跟您这儿写的量也差不多,但是愣是写不出来啊,没办法,噎在那儿出不了口,所以只好没事儿跟人说说,写是难办了。
另外问个事儿,现在有空上 MSN 吗?前仨月说忙个项目,现在该好些了吧?我的 MSN 在 SoobbJohn@Hotmail.com。
2007-09-23 16:00 | 随风流月      

#14楼 [楼主]   回复  引用  查看    

@anikin2008
不但应该写DEMO, 还应该画图, 我对这个做法在一些问题上的能力很有信心 :). 不过这些字已经耗费好几个小时了, 实在有点力不从心. 这也是我最近才开始实践的,以后我会更广泛的进行实践, 以确定在不同情况下的优劣. 等到空闲时间多些, 我会把代码和图补上.

@随风流月
议论文是我所擅长的 :) 项目说实在的就是我自己在做的一个小玩意儿. 说小是真不大, 但是一摸进去水很深, 时间不但没松快, 比我想象的还紧.. 这两天来博客园, 简直就是大放假了....
2007-09-23 16:30 | 怪怪      

#15楼    回复  引用  查看    

用BookManager这种贫血模型是非常实际的一种做法,否则日志的AOP,事务的AOP怎么注入进去呢?而贫血的Book更便于传递。
2007-09-23 16:31 | Spring.Cheung      

#16楼 [楼主]   回复  引用  查看    

@亚历山大同志
你真要命, 身体是革命的本钱好么?
2007-09-23 16:31 | 怪怪      

#17楼 [楼主]   回复  引用  查看    

@Spring.Cheung
BookManager不一定在什么情况下都和贫血划等号吧...

不过这个争论我不参与, 只是想从另一个方向上找找出路.

干正经事的去了...

2007-09-23 16:34 | 怪怪      

#18楼    回复  引用  查看    

不好意思,表达能力比较弱。
还是博主厉害,写了这么一大段的文字。佩服佩服。
一会写一下 第二步抽象,也就是想要总结一下,呵呵。
2007-09-23 17:42 | 金色海洋(jyk)      

#19楼    回复  引用  查看    

佩服楼主,这么长的一个文章,花了半个小时终于看完了。
争论很激烈,但这种争论就像信资还是信社一样,没有头。最好就像楼主所说大家将自己的经验写出来就足够了,一直关注,不过竟看到争论了,没学到什么东西。争论是抛砖引玉,砖是抛出去了,引不会来玉,就没意思了
2007-09-23 19:20 | jillzhang      

#20楼    回复  引用  查看    

真的很佩服博主,这么长。。。。
我已经很久没看这么长的文章了(今天也没看完),不过觉得挺好的,找个时间继续一定看完它。
2007-09-23 19:54 | 壁虎      

#21楼    回复  引用  查看    

其实讨论这些的意义并不是面向对象最大意义的所在,正如老邓说的,白猫黑猫捉老鼠的问题……况且空说无证倒也觉得洋洋洒洒这么多就显得时间有点浪费了……
其实真正遇到项目问题的时候貌似分析起来又不是Book和BookManager这样的简单的东西可以模仿的,或者说对业务的把握甚至比这些都重要,正如这里我们拿Book来做例证,事实上是因为大家都懂得Book为何物,现在换成银行的一个子系统,或者换成***销售的诸多黑幕,我们又如何更好地抽象……虽然我们也依然知道职责是多么地重要,很重要,并不断地去管理职责,但是发现我们力不从心的往往是对业务对象的理解,我们不可能参与到实际的工作中去,正如拿着地图看,永远没有到街上走走来得印象深刻……

#22楼    回复  引用  查看    

如果有实际的项目来支持,比一大堆文字论述要好得多
2007-09-24 00:18 | 紫色阴影      

#23楼 [楼主]   回复  引用  查看    

唉, 看来大家都没好好看, 我的重点并不是到底要不要Book和BookManager的问题, 只是最近这种讨论太多了, 所以顺便就多说了两句, 结果大家的眼光就只看见这个问题了....
2007-09-24 08:01 | 怪怪      

#24楼 [楼主]   回复  引用  查看    

@volnet(可以叫我大V)
你说的确实有理,但有的问题确实有些时候模型比较简单,才容易讨论。 比如支持Book.Save的同志中,除了AOP类似的解决办法,谁能较好的解决Book类稳定性的问题?

一个是达成Book类的较少修改,一个是如果需要序列化,需要其它处理,是否应该:Book.Save,Book.Serialize,Book.Method1,Book.Method2这样一直增加下去?或者在垂直的逻辑中,不断的扩充Book.Save,要么象有的朋友说的那样分离出去,再回调?

同时Book.Save有理又有在,无论数据->对象,还是对象->数据,考虑到数据和对象经常一起变化,所以恢复对象的部分确实应该留在对象内部,或对象的子类中。

“我们力不从心的往往是对业务对象的理解”。这个我赞同,所以我说,大家还是更多的都拿出自己的经验,而不是讨论,这样就能得到一个统计学上的结果,指导我们前进。
2007-09-24 08:27 | 怪怪      

#25楼    回复  引用    

有2个重要的理由让我支持贫血模型,一个是入门较容易,团队开发的时候如果使用充血模型的话经常引起大家对于职责界定的混乱,通常要花费很多的时间去讨论才能确定下来,否则的话最终出来的效果你会看到整个Business Object臃肿不堪.相比这下XXXManager的效果更好一些,大家有这个共识,也更容易实施,但不可否认,项目很大的情况下依然还是会出现一些XXManager膨胀的情况,还好有这种情况大家都能及时提出及时重构.另外一个理由,分布式的项目绝不使用充血模型,把Bussiness Object就是当做DTO来用,如果你使用充血模型的话,一旦项目需要扩展为分布式项目,所要付出的代价将比贫血模型要大很多.
2007-09-24 08:50 | eidolon [未注册用户]

#26楼    回复  引用  查看    

其实很多问题也就出在最后和数据库的交互
我觉得大家也都感觉到了问题

数据库的非OO本质和程序的OO特性格格不入哦

2007-09-24 17:22 | 徐少侠      

#27楼 [楼主]   回复  引用  查看    

@徐少侠
很多人都这么说, 其实不是这样. 如果仅仅是因为数据库不OO, 于是就不OO了, 世界上就没有OO的系统了. OO数据库最基本的数据存储也没有什么OO不OO的问题. 它们只是给我们加了一层罩而已.

要我说, 大家不要骂我 -__- , 就是大家(包括我), 懒得自己加这层罩罢了.

数据库Oo了, 那Cache的问题怎么办? Object.CacheMe()还是又嫌数据库功能不够? 其它问题呢? 其实大家总在自己认知Oo理解之中考虑Oo的合理性, 却不去考虑Oo(至少大家心里个人理解的Oo)的不合理性.

比如Object.Save(), Object.Serialize(), Object.Cache(), Object.Permit(), 发现一个Object可以大展拳脚的地方, Object就应该多一个或几个方法? 其实这都不是个什么具体讨论对象复杂还是简单的问题, 而是一个根本性问题, 只看愿不愿意费神去想罢了...

说白了想不想这些问题, 就是是不是一个合格的POO的标志, 想的多少的问题, 就决定了专家和一般人的区别. 另外就是得有机会实践并勇于实践, 因为像样的问题都是真正的实践中来的, 而结论也只能通过实践验证.

比如我吧看着嘴上和笔头的工夫也不少, 真到实际应用, 也经常是能省心就省心了...
2007-09-24 20:17 | 怪怪      

#28楼    回复  引用  查看    

@怪怪
比如我吧看着嘴上和笔头的工夫也不少, 真到实际应用, 也经常是能省心就省心了...
与我心有戚戚矣....
哈哈

平时真的不是那么专注的,只是有问题了才去救火.主动OO设计并不多见.
2007-09-25 13:13 | 徐少侠      

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-09-24 16:01 编辑过


相关链接:
所属专题: 关于面向对象的讨论