2005-01-02
域对象 & 面向对象 & 结构化编程
本来我尽量避免关于方法论方面的主义之争,但一些话如骨鲠在喉,不吐不快。
软件领域方法论大师的著作发人深省,通常代表着软件开发的未来模式。当然,我们在读大师之后,掩卷沉思之余,最好也保持自己的独立意见。
希望本文能够唤起一些对基本概念和基本功的重视(追逐新潮概念之余,同时也固本培源 :D)。
1. Domain Object的重新提出的背景
Domain Object并不是一个全新的概念,而是继承以前的纯面向对象开发的思路。
由于当前O/R Mapping, DAO开发结构的层次划分,导致出现了大量的纯粹数据对象。这些数据对象只带有getter, setter属性,而不具有属于自己的方法,起着Data Transfer Object的作用。
Domain Object 则是重新提出并进一步探讨纯面向对象编程的概念:对象不仅应该具有数据,而且应该具有自己的方法。
这个过程和Spring的出现过程很像。
EJB时代之前,大家本来就是采用着轻量编程模型,只是那个时候,轻量编程架构还不成体系。EJB时代中,还坚持轻量编程模型,难免被看作顽固保守。EJB时代之末,轻量编程架构Spring大获成功。
2. Domain Object的划分准则
Domain Object是纯粹的OO对象(这话说起来有些别扭 :-)。
Domain Object的划分就是Object属性和方法的划分。这个划分有没有准则?我的看法是,没有准则。
有这样的说法,面向对象的业务划分,就是根据实际生活中的具体事物进行划分。这可以作为一个大的指导原则,但没有具体的可操作性。
让程序中的Object完全映射实际生活中的Object,是人类的一个伟大理想,是人工智能,是虚拟现实。
下面举个例子。比如,withdraw, deposit两个方法,是放在Account类的里面还是外面?
方案一:
Account代表我的账户,代表我的一个身份,那么当然是一个主动的对象。
Account取钱,存钱是里所当然的。withdraw, deposit两个方法应该是Account的方法。调用方法:
account.withdraw(money)
account.deposit(money)
方案二:
Account就是户头,就是一个被动的金额数据记录。
User每次申请银行管理机构(出纳),AccountManager来操作这个Account。
调用方法:
AccountManager.withdraw(account, money)
AccountManager.deposit(account, money)
3. 面向对象的真正意义 – 多态
面向对象的真正意义并不是为了能够方便的把数据和操作封装起来,映射一个实际业务中的对象。如果是为了这个目的,我们永远找不到一个可操作的准则。
比如,上面的两种划分方法,在实际的类结构设计中都存在,都有一定的道理。而且还存在言之成理的更多的其他划分方法。
面向对象的真正意义,在于处理多态。
上面的两种划分方法,如果只存在一种Account类型的情况下(比如只有银行柜台账户),那么编程上没有根本的区别。只是这个加钱、减钱的动作的位置不同 -- 是在Account里面做,还是在AccountManager里面做?
在有多个Account类型的情况下,那情况就大不一样了。
比如,有电子信用卡远程帐户 ECardAccount,有柜台存折账户PaperAccount。这两种账户的业务规则都是不同的。
比如,电子信用卡远程帐户的取钱,要收取一定比率的手续费,而柜台存折账户就不需要。
这个时候,两种划分方法的编程上的优劣,就体现出来了。
按照第一种划法方法(姑且成为Domain Object法),只要为相同的Account接口,实现两个不同的类,ECardAccount,PaperAccount,分别实现不同的withdraw,deposit就可以了。
第二种方法,就有些麻烦了。需要在AccountManager里面用一个 if else,或者switch来判断Account的类型,是ECard信用卡,还是Paper存折。
没错,多态就是用来消除if else, switch的。把接口从具体实现抽取出来的目的,就是为了实现上的多态。这个例子也很简单,属于所有OOP课本的第一个入门例子的级别。
这里不厌其烦地举出这个基本例子,就是为了说明:如果有多态的需求,那么应该使用Domain Object,如果没有多态的需求,那么随便,怎么样方便痛快,就怎么设计。毕竟,我们追求的最终目标是清晰、明快、简洁的代码,而不是为了符合某种经典结构。
4. 系统分层分包 & 类、包之间的交叉循环引用
我们还是看上面的例子,假设只有一个Account类型。
按照第一种划分方法,withdraw和deposit两个方法都在Account类里面。
假设withdraw方法需要根据金额大小,去查另一个数据表Fee费用表的费率,以便计算手续费。account.withdraw()方法还需要调用FeeDAO的方法,或者由一个代理调用。不管是采用什么方式,account和其他类之间的关系就复杂起来。层次调用关系也复杂起来。account同时是数据对象,也是业务对象。
account的获取和使用过程如下:
Account account = AccountDAO.getAccount(...);// DAO引用了Account
account.withdraw(...);// 其中调用了FeeDAO, Account引用了DAO
假设account处于business层。我们看到,business层和DAO层之间出现了循环关联引用。DAO -> business -> DAO
当然,Account, AccountDAO,FeeDAO都可以是接口。而接口之间的交叉或循环引用,在面向对象设计中,是无可厚非的。比如,著名的Observer模式的Observer和Observable接口之间就是典型的交叉引用。
不过,我的本人习惯是,这种类之间、包之间、Jar之间的交叉循环引用,应该尽量避免。不为别的,就为了所谓的Unit Test,类、包的裙带关系也是越少越好。
我们再来看,按照第二种划分方法的情况,withdraw和deposit两个方法都在AccountManager类里面。
Account属于Data Transfer Object层,AccountManager属于business层。
我们来看Account的获取和使用过程。
Account account = AccountDAO.getAccount(...); // DAO引用account
AccountManager.withdraw(account, ...); //里面调用FeeDAO,
我们看到,business -> DAO -> DTO。层次之间没有交叉循环引用的情况。
5. 面向对象 vs 面向过程
面向对象,还是面向过程,这是个典型的关于方法论的争论话题。
有这样的观点,如果一个程序员从一开始就是用Small Talk这样的纯面向对象语言,而不是从C这样的过程语言转过去,那么就能够建立良好的面向对象思维。
我想,这也许是对的。但这里似乎有一种隐含的意思,好像面向过程的思维习惯是一个根深蒂固的痼疾,是阻碍面向对象方针贯彻的万恶之首。
以至于有这样的趋势,全面否认了面向过程编程的经典设计思想和丰富遗产。
我觉得,这对面向过程编程来说,是不公平的。至少对于C++, Java这种半面向对象语言来说,面向过程编程的基本功也是很重要的。很多情况下,OO用不好的原因,恰恰是因为面向过程编程的基本功不过关。
其实,系统分层这个思路,就是来自于面向过程编程的最基本原则 – 库函数的设计要上层调用下层,层与层之间不能交叉调用依赖。比如,操作系统内核,系统函数库,应用函数库的设计。
基本功这个东西,一点都不酷,一点都不时髦,但这是立身之本。
祝大家新的一年,与时俱进,固本培元。:-)
软件领域方法论大师的著作发人深省,通常代表着软件开发的未来模式。当然,我们在读大师之后,掩卷沉思之余,最好也保持自己的独立意见。
希望本文能够唤起一些对基本概念和基本功的重视(追逐新潮概念之余,同时也固本培源 :D)。
1. Domain Object的重新提出的背景
Domain Object并不是一个全新的概念,而是继承以前的纯面向对象开发的思路。
由于当前O/R Mapping, DAO开发结构的层次划分,导致出现了大量的纯粹数据对象。这些数据对象只带有getter, setter属性,而不具有属于自己的方法,起着Data Transfer Object的作用。
Domain Object 则是重新提出并进一步探讨纯面向对象编程的概念:对象不仅应该具有数据,而且应该具有自己的方法。
这个过程和Spring的出现过程很像。
EJB时代之前,大家本来就是采用着轻量编程模型,只是那个时候,轻量编程架构还不成体系。EJB时代中,还坚持轻量编程模型,难免被看作顽固保守。EJB时代之末,轻量编程架构Spring大获成功。
2. Domain Object的划分准则
Domain Object是纯粹的OO对象(这话说起来有些别扭 :-)。
Domain Object的划分就是Object属性和方法的划分。这个划分有没有准则?我的看法是,没有准则。
有这样的说法,面向对象的业务划分,就是根据实际生活中的具体事物进行划分。这可以作为一个大的指导原则,但没有具体的可操作性。
让程序中的Object完全映射实际生活中的Object,是人类的一个伟大理想,是人工智能,是虚拟现实。
下面举个例子。比如,withdraw, deposit两个方法,是放在Account类的里面还是外面?
方案一:
Account代表我的账户,代表我的一个身份,那么当然是一个主动的对象。
Account取钱,存钱是里所当然的。withdraw, deposit两个方法应该是Account的方法。调用方法:
account.withdraw(money)
account.deposit(money)
方案二:
Account就是户头,就是一个被动的金额数据记录。
User每次申请银行管理机构(出纳),AccountManager来操作这个Account。
调用方法:
AccountManager.withdraw(account, money)
AccountManager.deposit(account, money)
3. 面向对象的真正意义 – 多态
面向对象的真正意义并不是为了能够方便的把数据和操作封装起来,映射一个实际业务中的对象。如果是为了这个目的,我们永远找不到一个可操作的准则。
比如,上面的两种划分方法,在实际的类结构设计中都存在,都有一定的道理。而且还存在言之成理的更多的其他划分方法。
面向对象的真正意义,在于处理多态。
上面的两种划分方法,如果只存在一种Account类型的情况下(比如只有银行柜台账户),那么编程上没有根本的区别。只是这个加钱、减钱的动作的位置不同 -- 是在Account里面做,还是在AccountManager里面做?
在有多个Account类型的情况下,那情况就大不一样了。
比如,有电子信用卡远程帐户 ECardAccount,有柜台存折账户PaperAccount。这两种账户的业务规则都是不同的。
比如,电子信用卡远程帐户的取钱,要收取一定比率的手续费,而柜台存折账户就不需要。
这个时候,两种划分方法的编程上的优劣,就体现出来了。
按照第一种划法方法(姑且成为Domain Object法),只要为相同的Account接口,实现两个不同的类,ECardAccount,PaperAccount,分别实现不同的withdraw,deposit就可以了。
第二种方法,就有些麻烦了。需要在AccountManager里面用一个 if else,或者switch来判断Account的类型,是ECard信用卡,还是Paper存折。
没错,多态就是用来消除if else, switch的。把接口从具体实现抽取出来的目的,就是为了实现上的多态。这个例子也很简单,属于所有OOP课本的第一个入门例子的级别。
这里不厌其烦地举出这个基本例子,就是为了说明:如果有多态的需求,那么应该使用Domain Object,如果没有多态的需求,那么随便,怎么样方便痛快,就怎么设计。毕竟,我们追求的最终目标是清晰、明快、简洁的代码,而不是为了符合某种经典结构。
4. 系统分层分包 & 类、包之间的交叉循环引用
我们还是看上面的例子,假设只有一个Account类型。
按照第一种划分方法,withdraw和deposit两个方法都在Account类里面。
假设withdraw方法需要根据金额大小,去查另一个数据表Fee费用表的费率,以便计算手续费。account.withdraw()方法还需要调用FeeDAO的方法,或者由一个代理调用。不管是采用什么方式,account和其他类之间的关系就复杂起来。层次调用关系也复杂起来。account同时是数据对象,也是业务对象。
account的获取和使用过程如下:
Account account = AccountDAO.getAccount(...);// DAO引用了Account
account.withdraw(...);// 其中调用了FeeDAO, Account引用了DAO
假设account处于business层。我们看到,business层和DAO层之间出现了循环关联引用。DAO -> business -> DAO
当然,Account, AccountDAO,FeeDAO都可以是接口。而接口之间的交叉或循环引用,在面向对象设计中,是无可厚非的。比如,著名的Observer模式的Observer和Observable接口之间就是典型的交叉引用。
不过,我的本人习惯是,这种类之间、包之间、Jar之间的交叉循环引用,应该尽量避免。不为别的,就为了所谓的Unit Test,类、包的裙带关系也是越少越好。
我们再来看,按照第二种划分方法的情况,withdraw和deposit两个方法都在AccountManager类里面。
Account属于Data Transfer Object层,AccountManager属于business层。
我们来看Account的获取和使用过程。
Account account = AccountDAO.getAccount(...); // DAO引用account
AccountManager.withdraw(account, ...); //里面调用FeeDAO,
我们看到,business -> DAO -> DTO。层次之间没有交叉循环引用的情况。
5. 面向对象 vs 面向过程
面向对象,还是面向过程,这是个典型的关于方法论的争论话题。
有这样的观点,如果一个程序员从一开始就是用Small Talk这样的纯面向对象语言,而不是从C这样的过程语言转过去,那么就能够建立良好的面向对象思维。
我想,这也许是对的。但这里似乎有一种隐含的意思,好像面向过程的思维习惯是一个根深蒂固的痼疾,是阻碍面向对象方针贯彻的万恶之首。
以至于有这样的趋势,全面否认了面向过程编程的经典设计思想和丰富遗产。
我觉得,这对面向过程编程来说,是不公平的。至少对于C++, Java这种半面向对象语言来说,面向过程编程的基本功也是很重要的。很多情况下,OO用不好的原因,恰恰是因为面向过程编程的基本功不过关。
其实,系统分层这个思路,就是来自于面向过程编程的最基本原则 – 库函数的设计要上层调用下层,层与层之间不能交叉调用依赖。比如,操作系统内核,系统函数库,应用函数库的设计。
基本功这个东西,一点都不酷,一点都不时髦,但这是立身之本。
祝大家新的一年,与时俱进,固本培元。:-)
评论
lane_cn
2007-04-18
我觉得lz对rich domain的设计有些错误的观念,写了一篇回复,另开了一个帖子:
http://www.javaeye.com/topic/71492
http://www.javaeye.com/topic/71492
clamp
2005-01-07
age0 写道
前面我们已经作出假设:除Bussiness Service以外,系统的其他部分已经完成,要多先进有多先进,足以应付任何需求。
反对这个假设,失去实际意义。
这样导致你在考虑Business Service的时候忽略对于其它层的影响,而我恰恰认为这种影响是至关重要的。
在我看来,你所谓的系统架构是完全不涉及到业务逻辑的,仅仅是一个技术框架而已。
和主题里面的域对象完全是两码事,因此我认为你的观点偏离讨论主题……
age0
2005-01-06
上文所提的系统架构其实不算太复杂,只需要持续的技术资源投入,而且支撑这个架构所需的策略引擎、交互控制引擎和规则引擎也绝对不是拿来显摆的。不过这些课题并不在本文的探讨范围之内,如果要讨论的话我们可以另开专题。
前面我们已经作出假设:除Bussiness Service以外,系统的其他部分已经完成,要多先进有多先进,足以应付任何需求。现在我们剩下的工作只有一个:完成 Pure Bussiness Service 的设计,无须引入其他层面的问题。我们最好还是按部就班,从系统的第一阶段开始设计,并且不作任何预测,也就是说不要做超前设计,不会在第一阶段就提供能够满足第三阶段需求的系统。从最简单的系统开始,逐步演进,随着系统的扩展不断引入更先进的技术,再用各种原则标准来评判设计。
nihongye一开始就提供了第三阶段的方案,稍微超前了一点,我们稍后进入第三阶段的时候再一并讨论。
前面我们已经作出假设:除Bussiness Service以外,系统的其他部分已经完成,要多先进有多先进,足以应付任何需求。现在我们剩下的工作只有一个:完成 Pure Bussiness Service 的设计,无须引入其他层面的问题。我们最好还是按部就班,从系统的第一阶段开始设计,并且不作任何预测,也就是说不要做超前设计,不会在第一阶段就提供能够满足第三阶段需求的系统。从最简单的系统开始,逐步演进,随着系统的扩展不断引入更先进的技术,再用各种原则标准来评判设计。
nihongye一开始就提供了第三阶段的方案,稍微超前了一点,我们稍后进入第三阶段的时候再一并讨论。
age0
2005-01-06
七彩狼 写道
帖子的主题不是领域模型和面向对象吗?
“根据这些泛化关系抽象出来的系统架构”,难道不是根据这些实际的业务而抽象出来的吗?
如何设计业务架构与如何设计系统架构是属于两个不同层面的问题,如果以电影拍摄作为类比,那么设计业务架构就相当于编写剧本,而设计系统架构则是指导如何进行电影拍摄。写好剧本当然重要,但如何写好剧本与如何拍好电影基本上是风马牛不相干的两件事。
clamp
2005-01-06
age0 写道
我想说的是,我们无法预测未来,所以我们唯一知道的是Normal和VIP服务肯定会有差异,但无论差异是多是少、会不会在未来有所改变,都应该不会影响我们的架构设计。
坚决反对这样的架构设计……
要么过于抽象,无法适应实际的需要
要么过于繁复,实现成本太高
七彩狼
2005-01-06
age0 写道
我要提醒一下,帐户和储蓄方案不能说是我们此次讨论的核心问题,我们要讨论的主题并不是业务方案,而是系统设计,如何设计一个拥有良好的扩展及适应能力的系统架构才是我们关注的重点。这一次是以银行系统为例,下一次则可能是电信或者其他系统,如果能够捕捉到不同系统之间的共性,根据这些泛化关系抽象出来的系统架构相信会更能经受的起时间和环境的考验。
帖子的主题不是领域模型和面向对象吗?
“根据这些泛化关系抽象出来的系统架构”,难道不是根据这些实际的业务而抽象出来的吗?
age0 写道
不过既然引入了储蓄方案,我们就稍微调整一下系统架构,将Middle Service Layer细分为Bussiness Service Domain及Strategy Service Domain,这两个Domain虽然同在Middle Service Layer,但互相独立,为User Interaction Layer提供各自的服务。
User Interaction Layer也进行相应改造:
在验证阶段,交互系统在取得客户帐号(AccountID)进行身份验证的同时取得客户类型(AccountType),验证通过后向Strategy Service Domain发出查询请求,取回属于该类型客户的交互策略及储蓄方案,最后根据交互策略生成该类型客户的专用界面进入服务阶段。
在服务阶段,客户可以选取自己喜欢的储蓄方案,每一个储蓄方案都提供了完整的服务列表,交互系统可以根据这份列表向Bussiness Service Domain提出相应的服务请求。
所以即使加入了储蓄方案,我们的Bussiness Service Domian依然是独立的,完全不受影响,那么现在可以进入正题:如何设计Bussiness Service Domian的代理接口、如何组织系统架构、如何分配职责、如何决定对象粒度。至于如何设计User Interaction Layer及Strategy Service Domain则可以暂时搁置到一边。
说实话,我觉得这有点过于教条了,为了架构而架构,我相信没有任何实际的系统需要这样复杂冗长的体系结构。原本简单的事情,为什么要做的这么复杂呢。
partech
2005-01-06
age0 写道
至于partech的问题“需要明确一下你的需求,VIPWithdraw和VIPDeposit具体的内容是什么?它同普通客户的Withdraw和Deposit有什么区别?”
我想说的是,我们无法预测未来,所以我们唯一知道的是Normal和VIP服务肯定会有差异,但无论差异是多是少、会不会在未来有所改变,都应该不会影响我们的架构设计。
我想说的是,我们无法预测未来,所以我们唯一知道的是Normal和VIP服务肯定会有差异,但无论差异是多是少、会不会在未来有所改变,都应该不会影响我们的架构设计。
呵呵,这使我想起了XP关于推迟实施未来能力的策略,
将来的变化还是等到变化来临了再考虑吧,因为在将来
会更加了解实际的需求。现在我没有必要去猜它的差异。
另外,构架不是历史,应该可以适时修改。
age0
2005-01-06
七彩狼 写道
我只画出了储蓄的图,相信已经足够了。
其实,由下面的图,可以清楚的看出,对于Account帐户,其实他不关心到底是普通用户,还是VIP用户,Account帐户只是关心 储蓄方案和金额 这两个概念。
在我们的这个应用中,要实现多态的,不是Account帐户,而是储蓄方案这个业务类。
下面的图中,绘图8是领域模型图,绘图1是业务序列图,都是从纯业务的角度出发的。
其中,银行业务员和代理人,是两个角色概念,可能不存在实际对应的类。
客户,应该需要相对应的客户档案类。
帐户和储蓄方案是我们此次讨论的核心问题。
其实,由下面的图,可以清楚的看出,对于Account帐户,其实他不关心到底是普通用户,还是VIP用户,Account帐户只是关心 储蓄方案和金额 这两个概念。
在我们的这个应用中,要实现多态的,不是Account帐户,而是储蓄方案这个业务类。
下面的图中,绘图8是领域模型图,绘图1是业务序列图,都是从纯业务的角度出发的。
其中,银行业务员和代理人,是两个角色概念,可能不存在实际对应的类。
客户,应该需要相对应的客户档案类。
帐户和储蓄方案是我们此次讨论的核心问题。
我要提醒一下,帐户和储蓄方案不能说是我们此次讨论的核心问题,我们要讨论的主题并不是业务方案,而是系统设计,如何设计一个拥有良好的扩展及适应能力的系统架构才是我们关注的重点。这一次是以银行系统为例,下一次则可能是电信或者其他系统,如果能够捕捉到不同系统之间的共性,根据这些泛化关系抽象出来的系统架构相信会更能经受的起时间和环境的考验。
不过既然引入了储蓄方案,我们就稍微调整一下系统架构,将Middle Service Layer细分为Bussiness Service Domain及Strategy Service Domain,这两个Domain虽然同在Middle Service Layer,但互相独立,为User Interaction Layer提供各自的服务。
User Interaction Layer也进行相应改造:
在验证阶段,交互系统在取得客户帐号(AccountID)进行身份验证的同时取得客户类型(AccountType),验证通过后向Strategy Service Domain发出查询请求,取回属于该类型客户的交互策略及储蓄方案,最后根据交互策略生成该类型客户的专用界面进入服务阶段。
在服务阶段,客户可以选取自己喜欢的储蓄方案,每一个储蓄方案都提供了完整的服务列表,交互系统可以根据这份列表向Bussiness Service Domain提出相应的服务请求。
所以即使加入了储蓄方案,我们的Bussiness Service Domian依然是独立的,完全不受影响,那么现在可以进入正题:如何设计Bussiness Service Domian的代理接口、如何组织系统架构、如何分配职责、如何决定对象粒度。至于如何设计User Interaction Layer及Strategy Service Domain则可以暂时搁置到一边。
至于partech的问题“需要明确一下你的需求,VIPWithdraw和VIPDeposit具体的内容是什么?它同普通客户的Withdraw和Deposit有什么区别?”
我想说的是,我们无法预测未来,所以我们唯一知道的是Normal和VIP服务肯定会有差异,但无论差异是多是少、会不会在未来有所改变,都应该不会影响我们的架构设计。
clamp
2005-01-05
七彩狼 写道
同意楼上的观点,我这个储蓄方案的确简单了些,呵呵。
如果要想实现“产品定制”这样的复杂业务模型,可以参考《分析模式》中的“库存与帐务”一章中所讲的业务模型,MartinFlower还在这本书中讲了一个关于电信计费的实际例子。虽然是不同的业务,但和我们这里所建立的业务模型却是大同小异。
恩,没错,方法是可以借鉴的。
七彩狼 写道
另外,能否将这里的业务讲的详细一些,譬如:储蓄方案本身也是可以相互引用、复合性的方案-自动转存、等等,我来接着把储蓄方案的业务模型给画详细的出来。
呵呵,这个就涉及到非常具体的业务逻辑了。
我也不是专门做这个的,拿不出更详细的例子了……
七彩狼
2005-01-05
clamp 写道
不过我认为金额只是实例化的储蓄方案中的一个参数而已,和储蓄方案不是一个级别的。同样的参数还包括时间长短、类别等等。
另外,我认为储蓄方案本身也是可以相互引用的。
有一些是比较基准的方案,如:活期、定期等等
还有一些是复合性的方案,如:自动转存等等,甚至可以在已经复合的基础上再进一步复合,其衍生品几乎是无穷无尽的。
套一个概念叫“产品定制”。
另外,我认为储蓄方案本身也是可以相互引用的。
有一些是比较基准的方案,如:活期、定期等等
还有一些是复合性的方案,如:自动转存等等,甚至可以在已经复合的基础上再进一步复合,其衍生品几乎是无穷无尽的。
套一个概念叫“产品定制”。
同意楼上的观点,我这个储蓄方案的确简单了些,呵呵。
如果要想实现“产品定制”这样的复杂业务模型,可以参考《分析模式》中的“库存与帐务”一章中所讲的业务模型,MartinFlower还在这本书中讲了一个关于电信计费的实际例子。虽然是不同的业务,但和我们这里所建立的业务模型却是大同小异。
另外,能否将这里的业务讲的详细一些,譬如:储蓄方案本身也是可以相互引用、复合性的方案-自动转存、等等,我来接着把储蓄方案的业务模型给画详细的出来。
frankensteinlin
2005-01-05
引用
专业代理人需要系统提供什么样的服务来满足VIP的需求,需要描述清楚。
我想首先要搞清楚专业代理人能提供什么样的服务,它能做什么,专业代理人这个概念的引出到底是处理什么范围的事情?然后再想怎么满足它的需求。
由需求来订制业务,由上而下.
当然由下而上也有好处,先了解自己手头的工具,量力而行。工程师多半喜欢这样,并且可以炫耀新工具的功能,但这种功能真的需要么?我们不是搞科学研究的,还是看看能满足顾客上帝的需求吧!(发点牢骚)
clamp
2005-01-05
七彩狼 写道
其实,由下面的图,可以清楚的看出,对于Account帐户,其实他不关心到底是普通用户,还是VIP用户,Account帐户只是关心 储蓄方案和金额 这两个概念。
在我们的这个应用中,要实现多态的,不是Account帐户,而是储蓄方案这个业务类。
同意要实现多态的是储蓄方案。
同意图8中的三个基本对象:客户、帐户、储蓄方案。
不过我认为金额只是实例化的储蓄方案中的一个参数而已,和储蓄方案不是一个级别的。同样的参数还包括时间长短、类别等等。
另外,我认为储蓄方案本身也是可以相互引用的。
有一些是比较基准的方案,如:活期、定期等等
还有一些是复合性的方案,如:自动转存等等,甚至可以在已经复合的基础上再进一步复合,其衍生品几乎是无穷无尽的。
套一个概念叫“产品定制”。
partech
2005-01-05
clamp 写道
系统需求来自于业务故事啊,呵呵。
没错,但我们现在讨论的是系统设计,而不是需求分析。所以给定的输入应当是系统需求,而不是业务故事。
clamp 写道
我承认你的做法是一种解决方案,但是对专业代理人的要求比较高,他必须善于将手头各种简单的金融工具整合成一套完整的方案(就和前面设计的一样,类似于facade模式)。
不过这样的话,产品也未免太没有竞争力了。
Domain Object的重要意义之一我认为就是发现这种整合过后的复杂对象,以及其内部的复杂行为,而不仅仅提取出帐户这种简单对象。
这个问题我想首先是业务建模和需求分析问题,而不是系统设计问题。
专业代理人需要系统提供什么样的服务来满足VIP的需求,需要描述清楚。
也就是说系统用例要出来,否则谈到系统设计就是无根之木。
七彩狼
2005-01-05
我只画出了储蓄的图,相信已经足够了。
其实,由下面的图,可以清楚的看出,对于Account帐户,其实他不关心到底是普通用户,还是VIP用户,Account帐户只是关心 储蓄方案和金额 这两个概念。
在我们的这个应用中,要实现多态的,不是Account帐户,而是储蓄方案这个业务类。
下面的图中,绘图8是领域模型图,绘图1是业务序列图,都是从纯业务的角度出发的。
其中,银行业务员和代理人,是两个角色概念,可能不存在实际对应的类。
客户,应该需要相对应的客户档案类。
帐户和储蓄方案是我们此次讨论的核心问题。
其实,由下面的图,可以清楚的看出,对于Account帐户,其实他不关心到底是普通用户,还是VIP用户,Account帐户只是关心 储蓄方案和金额 这两个概念。
在我们的这个应用中,要实现多态的,不是Account帐户,而是储蓄方案这个业务类。
下面的图中,绘图8是领域模型图,绘图1是业务序列图,都是从纯业务的角度出发的。
其中,银行业务员和代理人,是两个角色概念,可能不存在实际对应的类。
客户,应该需要相对应的客户档案类。
帐户和储蓄方案是我们此次讨论的核心问题。
frankensteinlin
2005-01-05
引用
因为VIP同普通客户的区别已经被专业代理人屏蔽了,我看不出系统对于两者需要做出什么不同的处理
我有个小小的意见,让银行聪明一点,当发现自己的客户是VIP客户的时候,自动提供专业代理人给与服务?VIP仍然作为个客户与银行交流。不需要客户再脑门上写上我是VIP我要找xxx代理人给我服务?(JOKE)
clamp
2005-01-05
partech 写道
呵呵,我需要系统需求,你却给我业务故事。
如果是你故事的这种情况,我认为普通客户同VIP,系统只需要做一下标记就行了,添加一个VIPAgreement,表示该客户是VIP。因为VIP同普通客户的区别已经被专业代理人屏蔽了,我看不出系统对于两者需要做出什么不同的处理。
系统需求来自于业务故事啊,呵呵。
我承认你的做法是一种解决方案,但是对专业代理人的要求比较高,他必须善于将手头各种简单的金融工具整合成一套完整的方案(就和前面设计的一样,类似于facade模式)。
不过这样的话,产品也未免太没有竞争力了。
Domain Object的重要意义之一我认为就是发现这种整合过后的复杂对象,以及其内部的复杂行为,而不仅仅提取出帐户这种简单对象。
frankensteinlin
2005-01-05
引用
如果是你故事的这种情况,我认为普通客户同VIP,系统只需要做一下标记就行了。
过早的想到系统怎样做是不好的,容易陷入解决问题的思考,首先想到普通客户和vip都是客户,是两种不同的客户,他们之所以不同肯定有不同的行为。先把问题描述出来。然后再看如何解决。
partech
2005-01-05
clamp 写道
普通客户Deposit:
填存款单,拿现金到柜台,柜台确认,给帐户加上相应的钱,完毕
普通客户Withdraw:
填取款单,到柜台提交,柜台确认,取出现金,给帐户减去相应的钱,完毕
VIP Deposit:
打个电话给专业代理人“我要存钱”
专业代理人说:“你要哪一类型的?储蓄型?投资型?还是保险型?”
VIP说:“储蓄型”
专业代理人说:“总额多少?”
VIP说:“500万”
专业代理人说:“这里是一个500万存款、储蓄型的方案。其中300万存本行的5年定期。100万存1年定期。100万存活期。到期自动转存。给你开两个户头……”
VIP说:“100万活期太多了。另外我要六个户头。”
专业代理人说:“那就再转50万到1年定期。六个户头没问题”
VIP说:“OK。半小时以后把结果给我。”
专业代理人说:“OK”
VIP Withdraw:
VIP说:“我要取款”
专业代理人说:“要多少?怎么用?”
VIP说:“一笔买车,一次付清。另一笔临时周转一下,大概要三个月。”
专业代理人说:“哦,我查了一下您的各个户头,建议是这样的………………”
VIP说:“OK”
呵呵,随便举个例子,似乎有点复杂哦:P
呵呵,我需要系统需求,你却给我业务故事。
如果是你故事的这种情况,我认为普通客户同VIP,系统只需要做一下标记就行了,
添加一个VIPAgreement,表示该客户是VIP。因为VIP同普通客户的区别已经被专业
代理人屏蔽了,我看不出系统对于两者需要做出什么不同的处理。
clamp
2005-01-05
partech 写道
需要明确一下你的需求,VIPWithdraw和VIPDeposit具体的内容是什么?它同普通客户的Withdraw和Deposit有什么区别?
普通客户Deposit:
填存款单,拿现金到柜台,柜台确认,给帐户加上相应的钱,完毕
普通客户Withdraw:
填取款单,到柜台提交,柜台确认,取出现金,给帐户减去相应的钱,完毕
VIP Deposit:
打个电话给专业代理人“我要存钱”
专业代理人说:“你要哪一类型的?储蓄型?投资型?还是保险型?”
VIP说:“储蓄型”
专业代理人说:“总额多少?”
VIP说:“500万”
专业代理人说:“这里是一个500万存款、储蓄型的方案。其中300万存本行的5年定期。100万存1年定期。100万存活期。到期自动转存。给你开两个户头……”
VIP说:“100万活期太多了。另外我要六个户头。”
专业代理人说:“那就再转50万到1年定期。六个户头没问题”
VIP说:“OK。半小时以后把结果给我。”
专业代理人说:“OK”
VIP Withdraw:
VIP说:“我要取款”
专业代理人说:“要多少?怎么用?”
VIP说:“一笔买车,一次付清。另一笔临时周转一下,大概要三个月。”
专业代理人说:“哦,我查了一下您的各个户头,建议是这样的………………”
VIP说:“OK”
呵呵,随便举个例子,似乎有点复杂哦:P
partech
2005-01-05
age0 写道
经过一轮舌战之后,战局又开始出现向空对空进一步演化的趋势,为了避免本贴的继续沉沦,大家还是就事论事比较好。
还是以楼主的Account例子为基础,稍微加入变化以更接近真实情况。
我们有一个简单的银行系统为客户提供存取服务,根据市场情况经历了三个阶段的演变。
第一阶段,我们只有一种类型的客户,只提供单一的withdraw和deposit业务。
第二阶段,决定增加一种VIP客户,提供VIP专用的VIPWithdraw和VIPDeposit业务,原来的客户转化为普通客户,原来的业务也转化为NormalWithdraw和NormalDeposit。
第三阶段,再增加一种中层客户,Withdraw业务享受VIP服务,Deposit则采用Normal服务。
这个系统虽然简单,但也算是有代表性的,各位不妨尽情发挥。
还是以楼主的Account例子为基础,稍微加入变化以更接近真实情况。
我们有一个简单的银行系统为客户提供存取服务,根据市场情况经历了三个阶段的演变。
第一阶段,我们只有一种类型的客户,只提供单一的withdraw和deposit业务。
第二阶段,决定增加一种VIP客户,提供VIP专用的VIPWithdraw和VIPDeposit业务,原来的客户转化为普通客户,原来的业务也转化为NormalWithdraw和NormalDeposit。
第三阶段,再增加一种中层客户,Withdraw业务享受VIP服务,Deposit则采用Normal服务。
这个系统虽然简单,但也算是有代表性的,各位不妨尽情发挥。
需要明确一下你的需求,VIPWithdraw和VIPDeposit具体的内容是什么?它同普通客户的Withdraw和Deposit有什么区别?
- 浏览: 591947 次
- 性别:

- 来自: china

- 详细资料
搜索本博客
最近加入圈子
最新评论
-
网上银行的安全操作设计探 ...
其实浦发的动态手机密码也是一种很好的解决方案!
-- by cdredfox -
线程同步
线程同步就是线程排队 ----------------------------- ...
-- by java9981 -
网上银行的安全操作设计探 ...
这方面经验不多, 对这方面比较感兴趣.
-- by grandboy -
网上银行的安全操作设计探 ...
lz关于动态口令(动态令牌)的理解有偏差,请参照ras.com。银行内部设计核心 ...
-- by foodoo -
2008 奥运会开幕式 色彩 ...
楼上,不是LCD,是LED
-- by swflora






评论排行榜