Richie

Sometimes at night when I look up at the stars, and see the whole sky just laid out there, don't you think I ain't remembering it all. I still got dreams like anybody else, and ever so often, I am thinking about how things might of been. And then, all of a sudden, I'm forty, fifty, sixty years old, you know?

领域驱动设计 Domain-Driven Design

Part I: Putting the Domain Model to Work
    领域驱动讲求将领域模型作为领域专家、分析人员、开发人员之间交流沟通的核心。传统的瀑布模型方式下,缺乏有效的反馈机制,在链路上领域知识以不同的表现形式进行传递,知识的丢失容易造成需求与实现之间的断层。传统的迭代方式下,软件产品的优秀程度取决于开发者对领域知识的兴趣和掌握程度。

Chapter One. Crunching Knowledge
    领域模型是领域专家和分析人员互相沉淀知识的一个工具,它帮助分析人员理解领域知识,也为领域专家提供一个规范的表达形式,有条有理的描绘领域知识,分析、解决领域问题。另外,领域模型也是开发团队知识沉淀的一种方式,帮助开发人员了解他所从事的特定领域,提高建模技能。

Chapter Two. Communication and the Use of Language
    领域模型其实是一种语言,领域专家与分析人员、开发人员之间交流的通用语言。
    一开始,分析人员与领域专家需要对这个通用语言达成一致,双方能熟练的运用领域模型描述问题,表达、分析、处理问题。
    1. 领域模型不是图,图只是让核心、关键的概念清晰的呈现出来。图的表达能力有限,模型必须配备描述(需求采集会议中的口头描述,或文档中的文字描述),将图形所代表的意义,以及图形中没有呈现出来的规则、断言、细节进行补充,才能完整地表述需求。
    2. 领域模型的UML或者类UML图不能太细太完整,否则过于庞大的模型会干扰人的思维,阻碍对主要部分,或者复杂逻辑的梳理。业务总是被切分成一个个片断进行分析,在每一个片断里,画出几个主要的对象和交互逻辑,细节的部分用文字记录、描述。
    3. 领域模型中不应当出现设计、技术方面的术语,也不应当出现开发人员不理解的业务术语。
   
    图:讨论过程中手绘领域对象模型

    说明性模型:最好不使用UML,从而与领域对象模型明显区别开。
   
    图:Explanatory Models

    关于领域模型表达方法(UML图?Visio图?)的选择问题,标准的形式是使用UML,但如果领域专家或开发人员根本无法对UML图例形成清晰的概念(将UML图映射到领域对象、逻辑,或代码实现),将注定DDD方式应用失败。因为没有掌握语言就无法使用它正确交流。第三节中强调建模人员要直接与开发过程接触,重要的一个作用是确认开发人员对领域模型这个语言是否正确理解,确保代码实现保持了建模者要表达的意图。因此DDD的一个关键思想是建模人员自始至终维护领域模型这个语言,以及它表达的内容,向团队的各个角色(领域专家、开发人员等)诠释各个建模元素的含义,让各个角色掌握这个语言,运用它来表达、实现实际需求。这是分析人员最关键的职责,贯穿整个过程。
    领域逻辑的表达不要受UML图的约束,否则可能是问题所在,适当的描述就可以很好的解决这个问题。
    领域模型是语言,所以表达的准确性很重要。对英语系国家,在英语理解、英语词汇提取方面很自然,可惜Rose、PowerDesinger等都无法象QQ一样,在用户昵称和备注之间切换显示。所以项目需要花精力克服这个障碍。

Chapter Three. Binding Model and Implementation
    整个模型庞大关系错综复杂,会导致无法实现,模型应当清晰,拥有明显的边界而分出子模型。
    分析模型独立于设计模型方式不可取,领域模型需要同步反映领域业务、分析、设计、编码实现。
    建模人员必须直接与开发人员、与代码接触,把握代码实现过程中模型的约束,接受实现层面对模型的反馈。开发人员必须一定程度的参与模型讨论,与领域专家接触。

Part II: The Building Blocks of a Model-Driven Design
   
    图:A navigation map of the language of MODEL-DRIVEN DESIGN

    DDD跟Smart UI模式冲突。如何在界面快速的为Customer添加一个属性、定制一张报表,这些不是DDD需要考虑的。

Chapter Four. Isolating the Domain
    使用分层方式将领域模型隔离出来。
    基础结构层:例如ORM、消息服务、日志服务、安全服务等。领域层:纯粹的领域逻辑处理。应用层:协调、组织领域层、基础结构层,构造完整的业务操作,例如事务控制等应当在应用层完成。

Chapter Five. A Model Expressed in Software
    关键因素:Entity、Value Object、Service。
    1. 关联:关联设计的考虑(方向的设计等),简化关联的实现。NHibernate基于主映射端做级联更新。
    2. Entity:An object defined primarily by its identity is called an ENTITY,所以Hibernate在Identity映射、生成方式上提供强力支持,而对组合主建映射比较弱。
    3. Value Object:基于值是否可改变,是否可以共享考虑。Hibernate中数据类型的IsMutable属性是对这种情况的处理。
    4. Service:常见的形式如Manager等,特点是只做事情,无状态,不是实体和值对象固有的。注意区分领域服务和其它层服务,前者处理领域逻辑。
    5. 模块:好的模块划分提高系统清晰度,复杂的划分导致领域实现的分散甚至无法实现,丧失DDD的优势。

Chapter Six. The Life Cycle of a Domain Object
    1. Aggregates.
Aggregate root and boundary, reference issues, 实现生命周期、加锁范围等控制.
    复杂的关联导航会导致实现上陷入泥潭,丧失对领域焦点的把握能力,什么时候使用关联实现内聚,什么时候使用查询实现解耦,需要良好的把握。
    2. Factories. 工厂并非领域对象,只是一种设计构造,但它担任的是领域层的职责。从数据库加载聚合的各个部分,构造整个聚合对象,也是一种创建过程。
    3. Repositories. 也是设计构造,主要职责是CRUD,以及使用各种属性进行query的方法。Hibernate中Session的一个重要角色,就是作为全局通用repository基础(当然还有Unit of Work等其它职责)。它还不能完全算是repository,因为repository的目的,其一是封装数据库检索技术的繁杂性导致对领域模型的关注重点发生偏移,其二是防止领域逻辑封装的泄漏,Session的HQL、SQL Query等违背了第二点。对每个聚合体(例如采购订单)设计一个repository类,其实就是poor model中Impl/Manager类增删改查部分的逻辑。
    Repository与factory的区别,repository主要职责是查询,它将对象创建、加载委托给factory。

Chapter Seven. Using the Language: An Extended Example
    完整的示例,贯穿讲解整个第二部分的内容:Isolating the Domain, Distinguishing ENTITIES and VALUE Objects, Designing Associations, AGGREGATE Boundaries, Selecting REPOSITORIES, Walking Through Use Cases, Object Creation (Factory), Refactoring, MODULES等等。

Part III: Refactoring Toward Deeper Insight
    Deep models: 经过多次迭代重构之后,抽象层次较深,表现力较强的模型。
    Supple Design: 柔性设计,不断重构的产物。

Chapter Eight. Breakthrough
    这个例子excellent,06年刚好碰到过完全类似的情况。一个项目中客户对一个功能模块提出了挑战性的需求,经过仔细的分析,我发现应当从核心领域对象中再分离一个概念出来,不仅完美的解决当时的需求,之前10多家客户实施过程中的相关问题都能够非常优雅的解决。尽管最终的表现形式是设计上,你的类结构、关系不同了,但最关键的是领域模型上的突破,是基于对领域的深层理解消化后,在业务分析上的突破。一般它会给领域模型带来一些新的名词概念、系统功能模块,甚至是操作流程,但这些领域专家极为认同,更能应对复杂的领域业务。
    Don't become paralyzed trying to bring about a breakthrough. 没有什么标准、定律指导我们去完成某一个具体业务的分析、优化设计,参考成熟优秀的系统,参考象BPML、WfMC这样有限的参考模型和《Analysis Patters》,是一个捷径,但很多时候这些参考是空白的。基于DDD思想,在不断迭代重构的过程中加深对领域知识的理解沉淀,为突破创造条件,是一个不错的实践型方法。

Chapter Nine. Making Implicit Concepts Explicit
    开发人员必须敏锐的捕捉隐含概念:仔细聆听团队的表达用语,研究设计中不协调的地方以及专家看似矛盾的说法,查阅领域相关的文献,尽量挖掘隐含概念。

Chapter Ten. Supple Design
    柔性设计是隐含概念的补充,隐含概念挖掘出来后你的手头已经拥有了足够的materials,将这些材料组织成灵活的设计形式就是柔性设计范畴。要防止柔性设计变成overengineering,避免过分的抽象等间接层次的出现。
   
    图:Some patterns that contribute to supple design

    1. Intention-Revealing Interfaces: 名字即表达用意,主要在接口(公共对象的public方法)设计上,不要让写client的人对接口方法名摸不着头脑。是应该好好学英语呢还是应该开发个中文语言?
    2. Side -Effect-Free Functions: 边际效应/副作用 是状态的记录、改变造成,象deep copy(Hibernate等ORM中就用的很多)就是为了避免side effect。
    3. Assertions: design by contract的产物,就是在方法的组织设计上,避免出现理解上的多义性。通常情况下大家都是通过注释来进行说明,但DDD讲究代码就是对领域模型的一种描述。
    4. Conceptual Contours: 粒度、边界的精细设计优化问题。
    5. Standalone Classes: 降低关联依赖。
    6. Closure of Operations: 指返回值跟操作对象类型相同,主要用在值对象上,例如实数相乘结果仍然是实数,xslt转换xml后结果可以仍然是xml。在开源框架中这种模式经常可以见到。
    7. Declarative Design: 声明性设计的运用比较广泛,例如Hibernate使用xml配置映射关系,这就是一种声明,框架使用这个声明实现对象与数据库记录的转换操作,其它的例如流程引擎、一些MVC框架等等。
    一般通过反射或者代码生成实现,缺点:a) 表达能力的不足可能使模型受限,开发束手束脚;b) 代码生成的破坏性可能扰乱迭代过程。
    其它的形式:Domain-Specific Language, From the Ground Up(一些函数编成方法)等。

Chapter Eleven. Applying Analysis Patterns
    实例说明accounting model分析模式的使用。

Chapter Twelve. Relating Design Patterns to the Model
    说明领域模式和设计模式的区别:领域模式为领域问题提供模型,设计模式侧重于代码实现层面。
    拿Strategy, Composite模式示例了一下。

Chapter Thirteen. Refactoring Toward Deeper Insight
    低级的重构是觉得代码实现不合理,refactory一下。深层次的重构指领域模型层面,不断与领域专家对话,查看领域文献,参考分析模式等成熟模型。
    They see the risk of changing code and the cost of developer time to make a change; but what's harder to see is the risk of keeping an awkward design and the cost of working around that design. 这句话说的很好。

Part IV: Strategic Design
    把整个系统的设计图画在一面墙上,估计没有几个人能看懂;协作开发过程中,边界上的约束、断言等清晰程度,影响着开发过程控制和质量。因此在较高的层次,一些策略型的措施必不可少。

Chapter Fourteen. Maintaining Model Integrity
   
    图:A navigation map for model integrity patterns

    作者蜻蜓点水的提到下面这样一些开发场景,如何控制开发方式,确保模型的完整性,提供一点参考:
    1. Bounded Context: 两个团队协作开发,模型的重叠/交互部分,边界上下文是什么?两个团队都清楚吗?
    duplicate concepts: 同一个概念在两个团队中存在不同的实现。false cognates: 对某个东西,两个团队以为理解是一致的,实际上存在分歧/偏差而没有被察觉。
    2. Continuous Integration: 不是直到最后期限才进行集成,协作开发过程中分步骤地进行集成、测试,降低风险。但它会带来一些额外的成本开销。
    3. Context Map: 透过边界的代码复用、数据功能的集成是一种风险,应当使用一个转换实现,提供一个全局的上下文映射视图和文档说明,集中管理,避免边界上下文的混乱。
    4. Shared Kernel: 将两个团队模型重叠部分的一些子集作为共享部分维护。
    5. Customer/Supplier Development Teams: 协作团队之间存在上、下游关系,典型的一些情况是底层框架开发团队与具体应用开发团队之间。
    6. Conformist: 上下游团队不是同一个部门,或者由不同的人领导。
    7. Anticorruption Layer: 与外部系统集成时隔离层的设计。
    8. Separate Ways: 尽量避免集成。
    9. Open Host Service: 过多的子系统集成不能都使用转换来实现,应当提供标准的协议/服务。
    10. Published Language: 两个系统间的集成,实用任何一方的模型可能都不是理想的,采用一种标准/规范的交互协议可能是更好的选择。
    11. Unifying an Elephant: 多个模型的集成问题。

Chapter Fifteen. Distillation

Chapter Sixteen. Large-Scale Structure

Chapter Seventeen. Bringing the Strategy Together

    精髓思想在前面几章中,后面的实在看不下去了。前面描述的是DDD思想,实例说明,以及一些方法论上的东西。后面部分侧重在一些实现、项目管理过程控制层面,尽管是作者的一些宝贵经验之谈,但这种发散性的解说应用于实际项目状况是有待推敲的事情了。更何况很多情况,大家使用不同的设计思想、开发模式时,都有遇到和处理过。
    花了一整天看完,希望能给大家一些参考。

posted on 2007-07-16 01:16 riccc 阅读(3993) 评论(44)  编辑 收藏 网摘 所属分类: Architecture & Design

Feedback

#1楼 2007-07-16 09:03 fds2003[未注册用户]

难得园子里有人讨论DDD,以前都是在JDON,JAVAEYE看这方面的资料。   回复  引用    

#2楼 2007-07-16 09:18 紫色阴影      

这本书的确不错   回复  引用  查看    

#3楼 2007-07-16 09:25 brucenan999[未注册用户]

赞一下.

这本书看了很久,才看了几十页,还是LZ速度快啊,一天就看完了.

看来书还是要快快的读.
  回复  引用    

#4楼 2007-07-16 12:06 Justin      

一天!牛!   回复  引用  查看    

#5楼 2007-07-16 12:49 bobmazelin      

是翻译吗?俺很推崇DDD的,期待LZ多发能引发探讨的帖子!   回复  引用  查看    

#6楼 2007-07-16 13:29 yxonline[未注册用户]

支持,不错,正在看这本书呢:)   回复  引用    

#7楼 2007-07-16 14:09 勇敢的心[未注册用户]

不错, 赞一个。 后面是比较散, 最后两章还是有点总结性的意思。   回复  引用    

#8楼 2007-07-16 14:22 aa[未注册用户]

楼主太强了,我在看,但看的慢得很,希望楼主多写些这方面的文章   回复  引用    

#9楼 2007-07-16 15:21 aa[未注册用户]

另外我在实际开发中,发现一个比较严重的问题,就是DDD在.net平台如何实现,如果不借助于ORM,DDD只能停留在分析和设计阶段,到了编码就无法实现了,如果使用ORM,在.NET平台好象没有多少选择,现有的ORM都是非官方且没有经过大量项目验证的。   回复  引用    

#10楼 2007-07-16 15:34 etrip[未注册用户]

http://*** 特价机票一网打尽,逸程网.   回复  引用    

#11楼 2007-07-16 19:45 Anthan      

越看博主的文章,越觉得高深莫测啊。
怪不得你要离开,金鳞岂是池中物...
  回复  引用  查看    

#12楼[楼主] 2007-07-16 21:41 RicCC      

@fds2003
@bobmazelin
园子里难得形成有深度的讨论阿
文章内容是一个提纲挈领的目录,加上了自己的理解,目的是以后随时可以把DDD思想过一遍的
  回复  引用  查看    

#13楼[楼主] 2007-07-16 21:43 RicCC      

@brucenan999
@Justin
一目十行有时候可能抓不住要点的,仔细一点看还是比较好
  回复  引用  查看    

#14楼[楼主] 2007-07-16 21:44 RicCC      

@勇敢的心
恩谢谢,找时间再把后面两张看看
  回复  引用  查看    

#15楼[楼主] 2007-07-16 21:51 RicCC      

@aa
DDD跟是否使用ORM没有关系的,在实现层面,它只关注在把领域层清晰的隔离出来,把关注焦点集中在领域层的处理上,与领域模型保持一致
记得有一本以.net c#为例讲解DDD应用的书,具体内容不大清楚,大致的翻过一遍目录感觉比较杂,什么PoEAA、NHB、SOA、AOP好像都有提到,你可以参考一下
  回复  引用  查看    

#16楼[楼主] 2007-07-16 21:53 RicCC      

@Anthan
呵呵有点夸张了
  回复  引用  查看    

#17楼 2007-07-17 09:17 bobmazelin      

希望能形成对DDD的讨论才好啊...不仅仅是在理论层面上.   回复  引用  查看    

#18楼 2007-07-17 14:07 aa[未注册用户]

楼主说的没错,但分析与设计如果到了编码环节,最终无法很好的实现DDD的思想的话,分析和设计的作用就大打折扣了,哪本书我看了,所提的都还是一些开源的实现,现在.NET做企业应用,能不能用开源的,说实在是没信心的,而MS对DDD的支持,到了开发阶段,没有一整套方法,也是个大问题啊   回复  引用    

#19楼 2007-07-17 15:49 RicCC[未注册用户]

@bobmazelin
博客园适合分享,不大适合交流。以后有心得再写出来跟大家讨论。
如果只是关注代码实现方面,拿一些典型的例子验证一下是很简单的。在领域业务分析方面,还真不好讨论的。
  回复  引用    

#20楼[楼主] 2007-07-17 16:33 RicCC      

@aa
我不大清楚你的一个前提条件
如果使用表模块、事务脚本方式(.NET应用很容易产生出这种设计),想要运用DDD思想是很难,DDD的一个基础是OO思想
如果开始使用失血、贫血模型会比较好运用,DDD会导致你的精细化设计,很可能演化到最后成为充血模型
 
举个例子,使用失血、贫血模型,你会有DAO的定义
public class Costumer
{
    
private int _id;
    
private string _name;
    
private string _address;

    
public int ID
    {
        
get { return this._id; }
        
set { this._id = value; }
    }

    
public string Name
    {
        
get { return this._name; }
        
set { this._name = value; }
    }

    
public string Address
    {
        
get { return this._address; }
        
set { this._address = value; }
    }
}

如果不使用ORM,直接使用DAL的话就是下面这样了
public class CostumerRepository
{
    
private IDAL _DAL;
    
public CostumerRepository(IDAL dal)
    {
        
this._DAL = dal;
    }

    
public Costumer GetCostumer(string id)
    {
        Costumer customer 
= new Costumer();

        
//load data
        DataTable table;
        
try
        {
            
string sql = "select * from TblCostumer where CusId=@CusId";
            table 
= this._DAL.ExecuteForDataTable(sql, new string[] { "@CusId" }, new object[] { id });
        }
        
catch (Exception e)
        {
            
throw e;
        }

        
//mapping to domain object
        customer.ID = Convert.ToInt32(table.Rows[0]["CusId"]);
        customer.Name 
= Convert.ToString(table.Rows[0]["CusName"]);
        customer.Address 
= Convert.ToString(table.Rows[0]["CusAddress"]);

        
return customer;
    }
}

Repository类不属于领域层,它只是把对象持久化这样通用的任务剥离出来,归入到一个基础结构层中,让领域层代码简洁、清晰,终极的目标就是阅读领域层代码,就跟看需求文档一样,并且要清晰明了
 
至于在Repository里面是否使用ORM,跟DDD没有关系。能不能将领域模型运用DDD实现到编码的映射,得看分析师的功底和团队能力
  回复  引用  查看    

#21楼 2007-07-17 16:50 aa[未注册用户]

谢谢楼主的回复,就我目前的了解,.NET平台开发主流还是表模块和事务脚本,你提供这个例子很好,不过对复杂的业务系统(对如有复杂的对象之间关系),因为在MS平台,表模块的支持是原生的,导致很多开发人员下意识就会去用表模块的方式,对你提供这个例子这样的OO实现,我也没看到过大型的应用(看到过都是在JAVA平台上)。   回复  引用    

#22楼 2007-07-17 16:51 aa[未注册用户]

另外对我所说的复杂系统,我个人感觉还是充血模型要好一些,   回复  引用    

#23楼 2007-07-18 07:24 蛙蛙池塘      

有人翻译了吗?我记得一年多以前人们老讨论领域驱动开发   回复  引用  查看    

#24楼 2007-07-18 08:11 aa[未注册用户]

以前的讨论差不多都是在JAVA世界,哪儿有PO、BO
、DAO,可.NET世界全是typed dataset,事务脚本,我一直想看看MS世界最合适的实现是什么,是不是非得等LINQ?
  回复  引用    

#25楼 2007-07-18 09:41 RicCC[未注册用户]

第一数据量方面,使用SQL肯定比LINQ性能要好,但很多直接用SQL开发的系统性能不见得好到哪去的
第二并发支持方面,同时在线几十万人,使用NHibernate可能意味着项目失败,但这种系统专家们也不会首选DDD之类的应用方案

.NET还缺一个EJB的东西
  回复  引用    

#26楼 2007-07-18 10:50 bobmazelin      

个人认为DDD在复杂业务的情况下是推荐的模式,怎么实现这个模式从.Net现在的实际情况看,一般项目应用ORM比较吃力,即便是LINQ也只是部分实现ORM.我认为关键是设计时不能使用表模块思想的方式去设计,但实现可以.
即在你理清业务,设计业务对象时使用完整的模型,但实现可以从DataSet等这样的表对象上获利,比如:Typed DataSet等,都可以.
  回复  引用  查看    

#27楼 2007-07-18 11:58 aa[未注册用户]

bobmazelin 的想法不错,但在实际操作上可能会有相当大的困难,也就是说又多了一层转换,对开发人员、设计人员来说可能都会很痛苦   回复  引用    

#28楼 2007-07-18 12:05 aa[未注册用户]

对这个话题希望有更多人发表看法,毕竟.NET平台企业化应用现在解决方案好象很少,另外找到一篇文章大家可以看看,和这个有关,

http://www.avocadosoftware.com/csblogs/dredge/archive/2007/04/16/728.aspx

PS:没想到老外也会用"哭求"这样的标题,真有意思啊。
  回复  引用    

#29楼 2007-07-18 12:46 bobmazelin      

@aa
你说的不错,多一层转换,两方面看,第一是在项目的基础架构设计中尽量减少技术上的转化难度;第二,培养开发人员正确的开发思路,重点还是要开发也能理解模型,这样转换问题并不大.
  回复  引用  查看    

#30楼[楼主] 2007-07-18 14:15 RicCC      

@bobmazelin
@aa
波波说的对阿
从头到尾贯穿使用DDD,涉及的问题太多了。不管使用什么开发模式,各种各样的团队开发环境中,每天都有很多头痛的问题困扰各个负责人、管理者,能够一步步从DDD思想里面获取一些东西运用起来,是比较实际的
1. 是否还在采用顾问部门负责调研、写需求,分析人员进行分析、设计这样的方式?瀑布模型的缺陷早已经被实际证明了。DDD讲求由建模人员主导需求采集过程。
2. 所谓的架构师是否还只是在技术层面追求完美的框架,以尽可能的适应变化?DDD的中心是领域模型,是对领域业务的不断理解、分析、重构。技术框架只是辅助的、一些可选方案。
3. 设计、分析师是否是专职的,做完分析设计就得全力投入关键部分的开发,而没精力去管其他开发人员如何实现?DDD要求编码实现反映领域模型,也并非一定要每一行代码都是perfect,有时候必须基于现实做一些无奈的选择,但是把握其中的关键:尽量将与领域无关的操作隔离开,使领域层概念明显,代码清晰;分析设计师全力保证代码实现与领域模型的匹配,不管使用事物脚本还是其他方式,代码清晰的描绘了领域模型的需求就OK。
说白了,就是用一个全职的分析师、设计人员把这个断层给连起来,采用一些手段尽量让涉及领域逻辑处理的代码简洁,让分析师将领域模型跟代码mapping时不受太多干扰,我想这就是你目前最好的方式。
  回复  引用  查看    

#31楼[楼主] 2007-07-18 14:18 RicCC      

谁有精力可以在博客园主持个企业应用架构的研究圈子   回复  引用  查看    

#32楼 2007-07-18 14:18 aa[未注册用户]

bobmazelin 的想法,对成熟的团队来说,应该是比较好操作的,不过我现在面临的情况,就是团队中大部分人,习惯于.NET传统方式,对OO思想理解都非常困难(国企,团队结构很杂,没办法),能接受DDD的,就哪么几个人,但面临的项目,却是比较复杂的业务系统,这就是困扰我的地方,我想用DDD,带来的好处是很显然的,但对团队来说,学习的曲线也很大,沟通成本也会非常高。   回复  引用    

#33楼 2007-07-18 14:22 aa[未注册用户]

@RicCC
在博客园以前有一个企业信息化的圈子,不过不活跃
  回复  引用    

#34楼 2007-07-18 14:34 bobmazelin      

@aa
的确,我也有类似的想法,虽然我不在国企,但开发对模型的理解能力的确不高,特别是那些业务比较复杂,工期比较紧的项目,应用DDD对于项目涉及人员是需要魄力的.反过来说,能挺过这关的团队,很可能他们会成为比较优秀的团队,至少他们的进步会相对大.
@RicCC
虽然DDD可以抽象成一种开发流程/开发方法,但我个人暂时不会把DDD上升的项目管理层次上,主要原因还是DDD在国内不很成熟,有开发的原因,也有管理者的原因.现阶段,我推荐是在局部应用,首推分析过程.Matin有句很不错,"哪怕你只是想一想模型,也会受益匪浅的!"在分析过程中以模型的方式(不仅仅是对象模型)来推进对于项目后期大有裨益.只有分析过程的模型思想能够在整个团队展开,才能在设计,编码,甚至跨项目重用(MDA提倡的)等过程上展开,否则根基差,事倍功半的.
  回复  引用  查看    

#35楼[楼主] 2007-07-19 13:22 RicCC      

@bobmazelin
局部验证极可能妨碍整体把握度,最好是逐步完整的试验,例如
1. 分析人员在理论、方法、相关工具上的研究。
2. 分析人员完整的验证。从以前的项目中找一个典型功能,完整地试验。用试验的效果争取高层领导的支持。
3. 向团队成员传递、培训相关知识。
4. 用一个可以作为测试的项目,完整地实践。
  回复  引用  查看    

#36楼 2007-07-19 14:11 bobmazelin      

@RicCC
一步步来嘛,以现在的水平我个人认为分析能到水准的团队(不是个人,有不少个人分析能力很强)已经不多了,完整试验的结果恐怕会一知半解.
  回复  引用  查看    

#37楼 2007-08-15 02:24 longzf[未注册用户]

我前些日子买了这本书翻译的看了一遍,结果翻译的一团糟,还不如lz总结的好,如果这本书给lz翻译,结果肯定不错。   回复  引用    

#38楼 2007-08-22 22:23 aa[未注册用户]

问题1:Factory对象调用Repository对象中的方法,Repository对象把数据库中的数据封装成对象返回到Factory中,但是这个对象是无聚合关联的,然后Factory把多次Repository对象调用获得的多个对象创建关联,然后返回一个组装好聚合关系的根。请问LZ是否是这样?

问题2:Repository是否需要创建接口?

问题3:DDD中的聚合是否和传统UML的聚合不一样?传统的只是2个对象的关联关系,而在DDD中的聚合是不是两个以上对象组合的一个整体?
  回复  引用    

#39楼[楼主] 2007-08-23 11:39 RicCC      

@aa
1. 是的,Repository只是负责存取,它对对象的聚合结构是不了解的。聚合结构或者创建过程比较复杂的时候,才会创建Factory对象。
2. 这个就不一定了,看你的情况而定。你可以做一个接口+抽象类,实现单实体的CRUD等通用操作的范型方法,也是不错的。我的Repository都是有实现一个接口的,因为需要使用RepositoryA去创建RepositoryB。
3. 聚合/组合关系最基本的元素是两个对象,但一个业务/设计层面的聚合体并不只是包含一个聚合关系,例如汽车,包括车身、底盘、发动机等很多部分,只有把它们都聚合/组合起来才是完整的汽车。这个在DDD和OO思想中都是一致的概念。
  回复  引用  查看    

#40楼 2007-08-23 12:53 aa[未注册用户]

@RicCC
>1. 是的,Repository只是负责存取,它对对象的聚合结构是不了解的。聚合结构或者创建过程比较复杂的时候,才会创建Factory对象。
>2. 这个就不一定了,看你的情况而定。你可以做一个接口+抽象类,实现单实体的CRUD等通用操作的范型方法,也是不错的。我的Repository都是有实现一个接口的,因为需要使用RepositoryA去创建RepositoryB。

如果聚合不是很复杂,只有两个对象的之间聚合关联,那么就可以直接使用
>RepositoryA去创建RepositoryB。
这样的方式去创建聚合,而不添加工厂对象?如果这样的话Repository就要了解聚合结构了吧?

还有一个问题就是论坛的Forum,Topic,Message之间的关系是否是聚合关系?我认为他们之间不是聚合关系,因为聚合的子项只能通过根来导航访问,因为Forum,Topic,Message都可以被直接被单独的搜索出来,而且Message也可以被系统中的其他对象所引用,所以我认为他们的关系不是聚合关系。不知RicCC兄对此有何看法?
  回复  引用    

#41楼[楼主] 2007-08-23 16:16 RicCC      

我讲的不是很清楚,你的理解也有点问题
我的做法是,一个聚合体,只会有一个Repository,不管它聚合了多少对象,一个聚合体会有一个Implementation以及多个Dao类,如果业务复杂,Impl类的后面可能会有Factory等很多其它服务类,但对于聚合体的业务,都是通过Impl类暴露出来。
大致show一些代码吧
Repository:
public sealed class TemplateRepository : IRepository
{
    private ISession _session;

    public TemplateRepository(ISession session)
    {
        if(session==null)
            throw new Exception("the param ""session"" is null, can not create TemplateRepository");
        this._session = session;
    }

    public ISession Session
    {
        get
        {
            return this._session;
        }
    }

Implementation:
public class TemplateImpl : IImpl
{
    private TemplateRepository _repository;

    public TemplateImpl(IRepository repository)
    {
        if (repository == null)
            throw new Exception("the param ""repository"" is null, can not create TemplateImpl");
        if (repository is TemplateRepository)
            this._repository = repository as TemplateRepository;
        else
            this._repository = new TemplateRepository(repository.Session);
    }

    public IRepository Repository
    {
        get
        {
            return this._repository;
        }
    }

下面是一段测试代码,也就是application layer的样子:
[Test]
public void Box001_CreateBox()
{
    ISession session = TestSetup.GetSession();
    ITransaction tran = session.BeginTransaction();
    BoxDao box;
    try
    {
        BoxImpl boxImpl = new BoxImpl(new BoxRepository(session));
        string content = @"<ul>$books:{<li>$attr.Name$ ($attr.Title$)</li>}$</ul>";
        box = new BoxDao()
            .SetGeneral("Box001_1", "Box001_1", "1100", "", true)
            .SetContent(content, CmsEnumProviderType.Attr, "thoughtsoft.cms.test", "CMSTest.BoxProvider01");
        boxImpl.CreateAndSaveBox(box);

        content = @"<div>$Title$</div>
<div><img src=""$url$"" /></div>
<div>$description$</div>";
        TemplateImpl templateImpl = new TemplateImpl(boxImpl.Repository);
        TemplateDao template = templateImpl.CreateAndSaveTemplateExternal(CmsEnumProviderType.Attr, "..", "..", "..", "..", content);

        content = @"<div>
<div class=""header"">
<div><a href=""$wrapper_head_url$"">$wrapper_head_text$</a></div>
<div><a href=""$wrapper_more_url$"">$wrapper_more_text$</a></div>
</div>
<div>$attr$</div>
</div>";
        TemplateDao wrapper = templateImpl.CreateAndSaveTemplateWrapper("Tmpl001_2", "Tmpl001_2", content, " ");

        box = new BoxDao()
            .SetGeneral("Box003_1", "Box003_1", "1101", "", true)
            .SetParams(template.TemplateId
                , new BoxParamDao("Title", "标题", CmsEnumAttributeType.ProductSelector, 10, "box with wrapper 1")
                , new BoxParamDao("url", "图片url", CmsEnumAttributeType.UserInput, 10, "box with wrapper 1.jpg")
                 , new BoxParamDao("description", "描述", CmsEnumAttributeType.UserInput, 10, "box with wrapper 1 desc"))
             .SetWrapper(wrapper)
             .SetWrapperParam("wrapper head 1", "wrapper1.html", "", "", "more...", "more1.html");
        boxImpl.CreateAndSaveBox(box);

        tran.Commit();
    }
    catch
    {
        tran.Rollback();
        throw;
    }
    finally
    {
        session.Close();
    }
}

要使用RepositoryA去创建RepositoryB,是因为聚合体A跟聚合体B之间也会有关联,甚至是进一步的聚合关系,例如下面是BoxImpl里面的一个操作,从前面TemplateImpl的构造函数你可以看到这个创建过程
private void UpdateBoxInternal(BoxDao box)
{
    if (box == null) return;

    //save template, if needed
    if (!box.UseTemplate)
    {
        TemplateImpl templateImpl = new TemplateImpl(this._repository);
        templateImpl.UpdateTemplate(box.Template);
    }

    this._repository.UpdateBox(box);
}
  回复  引用  查看    

#42楼[楼主] 2007-08-23 16:20 RicCC      

你说的Forum,Topic,Message我不是很清楚,如果message是指topic的reply,那他们之间可能会是一个聚合关系,如果message指的是站内消息,那么这三者之间的关系是比较松散的,应该只是关联关系。   回复  引用  查看    

#43楼 2007-08-31 03:30 elie[未注册用户]

我感觉读书要科学读书,突出重点,楼主认为这本书重要的部分是哪几章?哪几章对于掌握DDD来说必须要看,哪几章暂时不需要看?   回复  引用    

#44楼[楼主] 2007-08-31 12:15 RicCC      

@elie
1-8章
  回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 814784




相关文章:

相关链接:

导航

News

搜索

 

常用链接

随笔分类

随笔档案

Ruby & Rails

其它

数据库

最新评论

  • 1. re: WSE 3.0 UsernameToken应用
  • 涉及到网络访问权限方面的问题,还得针对实际情况下多试试了
  • --Richie未登录
  • 2. re: WSE 3.0 UsernameToken应用
  • 非常感谢楼主,我试了你说的哪几种情况,好像也是不好使!!
    过两天再次和您探讨!!
    真的非常感谢!!
  • --autuam
  • 3. re: WSE 3.0 UsernameToken应用
  • storename跟机器名没有关系,你打开证书管理单元可以看到Personal(个人)这样一些目录,wse中的storename跟这些目录有个对应关系,msdn上可以查到机器在域环境下需要设置Netw...
  • --Richie未登陆
  • 4. re: WSE 3.0 UsernameToken应用
  • 使用catch (System.Web.Services.Protocols.SoapException error)没有异常。但是 catch(Exception e) { Console.W...
  • --autuam

阅读排行榜

评论排行榜