|
这个主题共有 9 回复 / 1 页 [
]
|
|
|
|
|
|
如何处理对象删除时引用的判断
|
发表: 2007年03月26日 14:19
|
回复
|
|
|
往往有这样的逻辑,一个产品如果被订单引用,则产品不能删除。因此删除产品的逻辑必须去检测是否有订单引用了该产品。原本订单模块依赖于产品模块的,但产品模块中却要知道“订单”这个概念。这显然产生了双向依赖的问题,如果再加入一个新的模块引用到产品,就要去修改产品的删除逻辑代码。如果避免双向依赖的话,我们可能会想到观察者模式,通过在删除逻辑前执行PreDeleteProductionEvent的事件,在订单中来实现对产品删除事件的注册。似乎可以解决这个问题,但考虑到对象被引用时删除检测这种情况在系统中是很常见的——你开发的任何业务对象都有可能再新的对象引用,而在你设计这个对象时是未知的。那么都采用观察者模式,好象给设计带来很大的工作量。不知道前辈们是如何处理这个常见的问题的。
|
|
|
|
|
|
re:如何处理对象删除时引用的判断
|
发表: 2007年03月26日 16:55
|
回复
|
|
>原本订单模块依赖于产品模块的,但产品模块中却要知道“订单”这个概念。这显然产生了双向依赖的问题
设计模式属于设计细节,前提必须是分析建模完成的情况下,现在你的建模就有问题,依靠设计模式再去解决问题,就很牵强。
“产品”很显然不应该关联“订单”的,避免双向关联,同时也避免双向依赖,一般产生双向依赖,主要分析方法没有采取Evans DDD这样建模方法来实现,将行为和属性混淆在一起,说到底,还是面向围绕数据表分析设计思维习惯造成的。
你现在需要做的是: 1.寻找一个OO的建模方法,重新分析需求,对"产品" "订单"等建模。 2.避免双向关联。 3.围绕模型,采取Model/Service架构来分离行为。
|
|
|
|
|
|
re:如何处理对象删除时引用的判断
|
发表: 2007年03月26日 22:05
|
回复
|
|
>“产品”很显然不应该关联“订单”的
我没有说“产品”要关联“订单”。而是在对产品进行删除的类里,必须要对订单进行查询,才能知道是否有订单引用到要删除的产品,这是客观存在的双向关联,难道这是“需求分析”的错误吗?现在的目的就是为了避免模块间的这种双向关联。
例如(不好意思,下面是用C#的代码,意思大家应该能明白吧):
产品模块:
public class Production { }
public class ProductionRepository { public static int Delete(Production prod) { if(OrderRepository.QueryOrderByProduction(prod).Count > 0) { //....提示不可以删除 } //...执行删除 } }
订单模块:
public class Order { public IList OrderItem; }
public class OrderItem { public Production Prod; public decimal Quantity; }
public class OrderRepository { public IList QueryOrderByProduction(Production prod) { // ...查询订购prod的所有订单 } }
大家可以看出,产品模块和订单模块,应该是订单模块依赖于产品模块,但是为了要判断是否有订单引用到要删除的产品,则在ProductionRepository.Delete里必须去调用OrderRepository。那么我现在的一种解决办法是:
产品模块:
public class ProductionRepository { public static event EventHandle BeforeDelete;
public static int Delete(Production prod) { if(BeforeDelete != null) { BeforeDelete(this, new ProductionDeleteArgs(prod)); } } }
public class ProductionDeleteArgs : EventArgs { private Production m_prod;
public ProductionDeleteArgs(Production prod) { m_prod = prod; } }
订单模块:
public class OrderRepository { public OrderRepository() { ProductionRepository.BeforeDelete += new EventHandle(this.OnBeforeDeleteProduction); }
public IList QueryOrderByProduction(Production prod) { // ...查询订购prod的所有订单 }
public void OnBeforeDeleteProduction(object sender, EventArgs e) { if(OrderRepository.QueryOrderByProduction(prod).Count > 0) { //....提示不可以删除 } } }
上面用到了C#里的委托的技术,实际上就是一个观察者模式的做法。通过BeforeDelete这个事件委托,在ProductionRepository.Delete里,只需要判断是否有存在删除前的事件,如果有则执行。而OrderRepository则将OnBeforeDeleteProduction注册到BeforeDelete上。这样实现了在删除产品里对订单的引用进行判断。同样的,在系统增加其它的模块的时候,可以采用同样的机制来增加产品删除前的引用判断。而在产品模块就不需反复变更代码。
用“产品模块”和“订单模块”是我想表达我的问题的一个简单例子,并不是我实际工作中的需求。但我想大家应该都会遇上这样的问题,不知道大家是用什么方式来解决的。
>“产品”很显然不应该关联“订单”的,避免双向关联,同时也避免双向依赖,一般产生双向依赖,主要分析方法没有采取Evans DDD这样建模方法来实现,将行为和属性混淆在一起,说到底,还是面向围绕数据表分析设计思维习惯造成的。
请问Banq兄,我是思想里真的有“面向围绕数据表分析设计思维习惯”吗?本身我是最反对用“表分析思维”的,也许是我的思维真的有错,还请指教,谢谢!
|
|
|
|
|
|
回复:re:如何处理对象删除时引用的判断
|
发表: 2007年03月27日 11:53
|
回复
|
|
>是否有订单引用到要删除的产品,这是客观存在的双向关联,难道这是“需求分析”>的错误吗?现在的目的就是为了避免模块间的这种双向关联。
现在才对你这个案例情况有进一步了解,其实我们陷入了双向关联或双向依赖的误区。
删除产品时,必须了解是否有订单引用到要删除的产品,这个是业务需求,按照Evans DDD,这应该是在领域层实现的,实际上这属于删除的一个约束条件,或者认为是是一条业务规则,或规格specification
在Evans DDD这书中说:业务规则不适合放于实体或值对象,但是也不能移出领域层,可以设计一个“谓词”对象。
由于对你的整个系统设计不清楚,我个人觉得你武断分了订单模块和产品模块,而不是依据领域层和服务层来划分。这个问题已经在下面帖子里讨论: http://www.jdon.com/article/31216.html
所以,目前看来还是由于你分析需求提炼模型时没有考虑仔细,导致这样问题需要依靠设计模式来解决,但是目前看牵强一些,当然不是不可以。
以上观点仅供参考。 [该贴被banq于2007年03月27日 12:00修改过]
|
|
|
|
|
|
re:如何处理对象删除时引用的判断
|
发表: 2007年03月27日 14:24
|
回复
|
|
>由于对你的整个系统设计不清楚,我个人觉得你武断分了订单模块和产品模块,而不是依据领域层和服务层来划分
我的问题是“如何处理对象删除时引用的判断 ”,“订单模块”和“产品模块”只是我用于表述我问题的一个假设。当然也可以举例成“产品管理模块”和“财务管理模块”。
我想软件按业务的功能范围来进行模块的划分,应该和DDD不冲突吧。领域层和服务层只是架构的一个划分,和模块应该不是同一个分类标准吧。我想Eric Evans也有提到模块的概念吧。引Evans DDD(第五章5.5节 P78页):一个优秀的设计模型,它的元素能很好地协同工作,适当地选择模块,将那些紧密联系的模型元素集中到一起。这些高度内聚的对象,具有相关的职责,可以将建模和设计的工作集中在单独一个模块中,从而把复杂度限制在一个范围内,使开发人员更容易处理。….如果你的模型是一本书,那么模块就是这本书的章节…
>在Evans DDD这书中说:业务规则不适合放于实体或值对象,但是也不能移出领域层,可以设计一个“谓词”对象。
我的设计里,也没有把删除逻辑放在实体“Production”里呀。那么就这个谓词对象的代码写的时候,它无法预知道未来会有什么新的对象会引用到要删除的“产品”呢。所以我才引入了观察者模式来改变依赖。如果一个程序员开发一个业务模块的话,这个问题才会上升到模块中来。也就是我可以先开发出“产品管理模块”,再开发出“订单管理模块”或“财务管理模块”,那么在开发“产品模块”时,不知道后面还会有财务管理模块,不知道新的模块中有什么类会产生对产品的引用,导致产品不可以物理删除吧。
> 导致这样问题需要依靠设计模式来解决 呵呵,我开这个贴,目的就是想知道“如何处理对象删除时引用的判断 ”这个问题时,大家是怎么解决的。是否可以把您的做法告知一二呢,谢谢
|
|
|
|
|
|
re:如何处理对象删除时引
|
发表: 2007年03月27日 15:50
|
回复
|
|
|
|
|
|
|
|
回复:re:如何处理对象删除时引用的判断
|
发表: 2007年03月27日 17:47
|
回复
|
|
可能对DDD有些认识分歧,讨论一下:
>我想软件按业务的功能范围来进行模块的划分,应该和DDD不冲突吧。 个人认为不应该按业务的功能范围来进行模块的划分,Evans DDD的第15章 精练中,专门提到隔离核心,按照是否属于核心领域来进行模块划分,分为核心模块和辅助子模块等。
你的这个案例,product和Order显然属于业务核心,Product和Order是一个关联关系,不能将其强行切开分离到产品模块和订单模块,它们应该属于你这个业务系统的核心模块。
如果按照我的这个想法划分,就不存在你提出的问题,所以,我觉得问题出在分析建模划分上。
>也没有把删除逻辑放在实体“Production”里呀。那么就这个谓词对象的代码写的>时候,它无法预知道未来会有什么新的对象会引用到要删除的“产品”呢
如果划分到核心模块,那么谓词对象是在核心模块中,你会为Order建立一个规则谓词对象,作为删除的约束...。
如果你将来有新的会引用到要删除的“产品”呢,注意这个对象潜含义是模型对象,模型发生变化,一定是分析源头有变化,那么模型类图都要变化,整个分析设计代码再来一次迭代,因为这涉及业务的变化,我们程序员不会拍脑袋想出一个新模型对象。
如果想将这新的对象延伸开来,不想指模型对象,那么我们还是要就事论事,看这个对象首先是不是模型对象,如果是,按照上面思路实现;如果不是,再看具体情况,这个时候才可能会使用设计模式来解决问题。
个人意见..
|
|
|
|
|
|
re:如何处理对象删除时引用的判断
|
发表: 2007年12月22日 13:36
|
回复
|
|
我个人感觉banq的讨论有些牵强,有些跑题. >你的这个案例,product和Order显然属于业务核心. OK,我们可以划分到核心业务中,没有什么问题.但是我们实际项目中很可能对核心业务再划分成N个功能模块. 对这些核心业务下面的一些引用规则业务判断怎么处理? 以至整个系统业务引用规则怎么判断,系统怎么实现,才是这个贴的讨论主题吧
|
|
|
|
|
|
回复:re:如何处理对象删除时引用的判断
|
发表: 2008年03月28日 17:00
|
回复
|
|
这位 RoamsWind 兄弟说的很有道理 其实 举一个范围最广的例子, 系统的用户管理 所有系统的业务操作,基本上都会和该系统的用户有关联, 那么我删除用户的时候,肯定会考虑到该用户关联的所有的业务数据该怎么处理的问题,也就是本帖的贴主提出的问题,要校验和该用户相关的那些记录该怎么处理,是否需要进行校验等等。
我现在也想知道的是,banq遇到是怎么处理这个问题的呢?
我一般的解决思路是:要么不让删除,要么逻辑删除。 [该贴被elegantyu于2008-03-28 17:01修改过]
|
|
|
|
|
|
回复:如何处理对象删除时引用的判断
|
发表: 2008年03月29日 09:05
|
回复
|
|
我前面已经说了,可能没说明白:如果你将来有新的会引用到要删除的“产品”呢,注意这个对象潜含义是模型对象,模型发生变化,一定是分析源头有变化。
我的观点就是说如果想找一个自动设计机制帮助你解决业务领域"处理对象删除时引用的判断"是无解的,因为你不可能预测将来,这属于过度设计了,这就象有人试图通过开发一个系统能够对付大多数企业应用,也就是说:试图通过设计领域来解决前端分析领域的问题,有些本末倒置。
在分析业务模型时,通过双向关联来保证对象一致性,至于未来可能发生的关联,你无法预测,也不可能通过一个设计机制一劳永逸,到时针对具体情况,还必须返回分析建模阶段,具体情况具体分析。
|
|
|
|