论道WP(三):应用程序栏
作者通过具体翔实的例子介绍了Winodws Phone 7中应用程序栏的使用方式。
该内容已经被标记书签!
标记书签错误,请重试!

作者 池建强 发布于 2011年8月17日
软件系统面向对象的设计思想可谓历史悠久,20世纪70年代的Smalltalk可以说是面向对象语言的经典,直到今天我们依然将这门语言视为面向对象语言的基础。随着编程语言和技术的发展,各种语言特性层出不穷,面向对象是大部分语言的一个基本特性,像C++、Java、C#这样的静态语言,Ruby、Python这样的动态语言都是面向对象的语言。
但是面向对象语言并不是银弹,如果开发人员认为使用面向对象语言写出来的程度本身就是面向对象的,那就大错特错了,实际开发中,大量的业务逻辑堆积在一个巨型类中的例子屡见不鲜,代码的复用性和扩展性无法得到保证。为了解决这样的问题,领域驱动设计提出了清晰的分层架构和领域对象的概念,让面向对象的分析和设计进入了一个新的阶段,对企业级软件开发起到了巨大的推动作用。
本文主要介绍了领域驱动设计的基本概念、要素、特点,对比了事务脚本和领域模型的特点,最后介绍了我们在软件开发过程中的领域驱动设计实践。
2004年著名建模专家Eric Evans发表了他最具影响力的书籍:《Domain-Driven Design –Tackling Complexity in the Heart of Software》(中文译名:领域驱动设计—软件核心复杂性应对之道),书中提出了“领域驱动设计(简称 DDD)”的概念。
领域驱动设计事实上是针对OOAD的一个扩展和延伸,DDD基于面向对象分析与设计技术,对技术架构进行了分层规划,同时对每个类进行了策略和类型的划分。
领域模型是领域驱动的核心。采用DDD的设计思想,业务逻辑不再集中在几个大型的类上,而是由大量相对小的领域对象(类)组成,这些类具备自己的状态和行为,每个类是相对完整的独立体,并与现实领域的业务对象映射。领域模型就是由这样许多的细粒度的类组成。基于领域驱动的设计,保证了系统的可维护性、扩展性和复用性,在处理复杂业务逻辑方面有着先天的优势。
领域驱动的核心应用场景就是解决复杂业务的设计问题,其特点与这一核心主题息息相关:
面对复杂的业务场景和需求,如果没有建立和实现领域模型,会导致应用架构出现“胖服务层”和“贫血的领域模型”,在这样的架构中,Service层开始积聚越来越多的业务逻辑,领域对象则成为只有getter和setter方法的数据载体。这种做法还会导致领域特定业务逻辑和规则散布于多个的Service类中,有些情况下还会出现重复的逻辑。我们曾经见过5000多行的Service类,上百个方法,代码基本上是不可读的。
在大多数情况下,贫血的领域模型没有成本效益。它们不会给公司带来超越其它公司的竞争优势,因为在这种架构里要实现业务需求变更,开发并部署到生产环境中去要花费太长的时间。
下面我们简单介绍一下领域驱动设计的分层架构和构成要素,这部分内容在Eric Evans的书中有非常详尽的描述,想要详细了解的,最好去读原版书籍。
下面这张图是该书中著名的分层架构图,如下:
整个架构分为四层,其核心就是领域层(Domain),所有的业务逻辑应该在领域层实现,具体描述如下:
|
用户界面/展现层 |
负责向用户展现信息以及解释用户命令。 |
|
应用层 |
很薄的一层,用来协调应用的活动。它不 包含业务逻辑。它不保留业务对象的状态, 但它保有应用任务的进度状态。 |
|
领域层 |
本层包含关于领域的信息。这是业务软件 的核心所在。在这里保留业务对象的状态, 对业务对象和它们状态的持久化被委托给 了基础设施层。 |
|
基础设施层 |
本层作为其他层的支撑库存在。它提供了 层间的通信,实现对业务对象的持久化, 包含对用户界面层的支撑库等作用。 |
领域驱动设计除了对系统架构进行了分层描述,还对对象(Object)做了明确的职责和策略划分:
当然,DDD中还提出了聚合和聚合根(Aggregate Root)的概念,不过我们在实践过程发现聚合根有问题复杂化的倾向,用传统的聚合、组合等概念去描述领域对象之间的关系更容易理解,所以这里对这个概念就不做介绍了。
Martin Fowler 2004年所著的企业应用架构模式(Patterns of Enterprise Application Architecture)中的第九章领域逻辑模式(Domain Logic Patterns)专门介绍了事务脚本(Transaction Script)和领域模型(Domain Model),理解这两种模式对设计和构建企业应用软件非常有帮助,所以有必要介绍一下。
事务脚本:
事务脚本的核心是过程,通过过程的调用来组织业务逻辑,每个过程处理来自表现层的单个请求。大部分业务应用都可以被看成一系列事务,从某种程度上来说,通过事务脚本处理业务,就像执行一条条Sql语句来实现数据库信息的处理。事务脚本把业务逻辑组织成单个过程,在过程中直接调用数据库,业务逻辑在服务(Service)层处理。
事务脚本模式可以简单的通过UML图表示成这样:
由Action层处理UI层的动作请求,将Request中的数据组装后传递给BusinessService,BS层做简单的逻辑处理后,调用数据访问对象进行数据持久化,其中VO充当了数据传输对象的作用,一般是贫血的POJO,只具备getter和setter方法,没有状态和行为。
事务脚本模式的特点是简单容易理解,面向过程设计。对于少量逻辑的业务应用来说,事务脚本模式简单自然,性能良好,容易理解,而且一个事务的处理不会影响其他事务。不过缺点也很明显,对于复杂的业务逻辑处理力不从心,难以保持良好的设计,事务之间的冗余代码不断增多,通过复制粘贴方式进行复用。可维护性和扩展性变差。
领域模型:
领域模型的特点也比较明显, 属于面向对象设计,领域模型具备自己的属性行为状态,并与现实世界的业务对象相映射。各类具备明确的职责划分,领域对象元素之间通过聚合和引用等关系配合解决实际业务应用和规则。可复用,可维护,易扩展,可以采用合适的设计模型进行详细设计。缺点是相对复杂,要求设计人员有良好的抽象能力。
领域模型对应的就是领域驱动设计中划分的领域层,这里就不详细讨论了。
在实际的设计中,我们需要根据具体的需求选择相应的设计模式。具备复杂业务逻辑的核心业务系统适合使用领域模型,简单的信息管理系统可以考虑采用事务脚本模式。
下面主要讲一下我们在构建企业级应用开发平台中对DDD的实践和扩展。
本人近年来一直在从事企业级应用开发平台的相关工作,GAP平台是我们的一个软件产品,用来解决企业级软件开发过程中复用、快速开发和过程规范等问题。设计这样一个平台,从底层的框架上就应该能够支撑复杂业务逻辑的系统构建,所以我们在大的架构设计思路上采用了领域驱动设计的思路,并根据实际采用的技术和要实现的功能对DDD的四层架构进行了细化和实现:
整个平台采用了JavaEE的技术及其相关的开源框架。系统的核心业务逻辑由Domain层处理,其中的业务服务(BusinessService)负责处理某个相对内聚的业务逻辑单元,同时对内对外提供本地或远程的服务。
下面是对各层的简要描述:
另外,我们引入了Spring的IOC容器,系统的控制层、领域层和持久化层元素都有IOC容器统一管理,实现完全的接口分离和解耦。同时在控制、领域和持久化层都可以引用日志服务。
我们对领域驱动要素的定义上和原有的命名和含义上稍有区别。
原来的服务(Service),我们定义为业务服务(BusinessService),面向业务服务的架构是GAP平台的核心设计思想,一个业务服务可以由一个或多个领域模型和数据访问对象(DAO)组成,去实现一个完整的业务逻辑单元。业务服务主要负责事务处理和维护各个领域对象之间的关系,同时为上层访问提供本地和远程服务,服务类型包括Web Service,RMI等。
领域对象由实体(Entity)和值对象(VO)构成,实体类具备自己的属性和行为、状态,可以聚合VO,实体类之间可以有聚合关联等关系,可以由数据访问对象(DAO)进行持久化。
持久化由数据访问对象(DAO)实现,不处理业务逻辑,主要负责实体类的持久化。提供多种持久化方式(O/R Mapping和JDBC)。
那么如何在去实现领域驱动设计呢?我们总结了以下四个步骤:
为了更好的理解领域驱动设计,我们基于以上设计方法,实现了一套简单的网上书店系统。
网上书店系统是采用DDD设计思想构建的一个应用系统示例。通过网上书店系统,可以快速理解领域驱动设计。该系统实现网上书店的常用功能:包括浏览书籍、挑选书籍、提交订单、查看订单、自动折扣、处理订单、取消订单等。未登录用户可以浏览和挑选书籍;已登录用户可以提交和查看自己相关的订单;管理员可以处理订单。
经过业务抽象,即使是这样一个简单的业务场景也包含了很多领域对象,例如订单、账户、书籍、购物车、购物项、折扣等,通过分析和设计,我们可以得到这样的设计图(为了查看方便,图中的类隐藏了属性信息):

BookStoreAction负责处理展现层的请求,并把请求转发给业务服务IBookStoreBS,业务服务负责调度上图中显示的领域对象,处理该场景的所有业务。
其中领域对象和现实业务的对应关系为:
与事务脚本的编程模式不同,领域驱动设计不是把业务逻辑放在BS(BusinessService)中,而是由具备属性、行为和状态的领域对象处理。例如Order类,如果是贫血的POJO,那它内部只有与数据表字段对应的属性以及getter和setter方法,而在领域驱动设计中,则是一个相对独立的、能够处理自身关联业务的领域对象。在本系统中,我们对Order的描述如下:
订单的实现类是gap.template.bookstore.model.Order,类中除了联系方式、邮寄地址等基本属性外,还有以下领域相关的行为:
通过以上的描述,我们可以看到,Order类基本上覆盖了现实世界中订单这个业务的所有行为和状态,是相对内聚的,这样的特性使其复用性大大增加,即使未来开发新的模块,涉及到订单业务的,可以直接复用Order类。同时在后期维护中,如果我想了解订单的业务,直接读Order的代码就可以了。
从上图中我们还可以清晰的看到各个领域对象之间的关系。Order和Cart都聚合了Item,对应都是1...n,Item聚合了Book,对应关系1...1。Order分别与折扣、账户发生关联和调用等等,整个网上书店的场景就这样描述出来了。
另外,不要忘了BS,除了起到基础设施的作用外(事务管理和服务共享),它还要负责调度和维护领域对象之间的关系。因为总会有些业务逻辑,既不属于这个领域对象,也不属于那个,那这部分业务由谁来处理呢?由BS来处理。例如在管理员处理订单这个场景中,首先需要根据订单信息获取账户,根据账户信息确定折扣率,同时进行余额校验,如果校验通过,就会调用订单对象的dispose方法处理订单,这个场景会涉及到Order、Account、Discount等对象,这样的业务逻辑,应该由BS实现。
IBookStoreDao是数据访问对象,可以被BS调用,用来持久化对象,也可以被领域对象引用,用来持久化自身。
通过以上的描述,我们可以看到,整个设计和实现是优雅、清晰的。业务逻辑没有堆积在BS中,而是分散在BS和各个领域对象中,服务和对象都与现实世界的业务息息相关,无论是对领域专家、开发人员和后期维护人员,都能这种方式中获得自己需要的内容。
我们采用领域驱动设计相对比较早,就我个人的检验和实践而言,DDD对构建企业级应用开发平台和大型核心业务系统的作用是非常明显的,无论是在产品的稳定性、扩展性、可维护性、生命周期等方面都有显著的提升。
但是,由于这样那样的原因(复杂度、工期、开发人员能力限制等等),很多人会不自觉的抵制采用DDD,有时候一个软件项目重写了两次,第二次依然不去做良好的设计。事实上采用了DDD的设计方法,我们的设计阶段已经变得非常轻量级和敏捷了,开发人员只要能够把领域模型之间的关系画出来并描述说明,并与需求人员达成一致,那么做出来的东西基本上是靠谱的。
在技术领域,只有主动的尝试和提升,效果才是最明显的。很多人问过我,如何开始学习和实践XXX,其实很简单,现在就开始吧!
《 领域驱动设计—软件核心复杂性应对之道》,Evans Eric著,Addison-Wesley出版社
《企业应用架构模式》, Martin Fowler著, Addison-Wesley出版社
感谢张凯峰对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。
写的很好。
Thanks :)
看过不少关于架构方面的书籍,但是鲜有人,对如何建立领域模型,进行过深入的讨论?能否给予指点?或许我的面向对象设计的能力较差。设计系统时,总是不知道该如何设计领域模型。非常感谢。
写的很好,意犹未尽呀。
是不是通俗地说就是Entity中调用Dao?需要跨多实体业务的数据库事务如何控制?
这方面只能具体问题具体分析了,事实上DDD只是提供了一种方法,让大家更好的利用这种方法进行设计,实际业务的抽象还需要领域专家和开发人员来做的,所以没有银弹么
事务是通过Spring的声明式事务管理来控制的,一个BS中引用多个DOA,那么这些DAO中的事务就是一致的。
“胖服务层”和“贫血的领域模型”的出现,是分析阶段的工作不足造成的。可以说是还没有领会到面向对象分析设计的真谛。这种“贫血的领域模型”,实际上就是一个个数据结构;而“胖服务层”,则是一个个实现过程。
是否采用某种设计概念,如领域驱动,并不是最重要的。重要的是真正以面向对象的思想来进行分析和设计。也就是说,我们最终得到的是什么?是一个个机能?还是一个个职责,由这些职责来实现各个机能?
如果不能区分机能与职责,估计用什么设计概念,也无法做到面向对象设计。
我认为,首先应正确认识此文的作用,此文仅仅是关于DDD的介绍(Introduction),千万不要当成解决方案(Solution)。
DDD的核心价值在于其分析方法以及对领域对象的职责划分原则,产出的结果应是与实现无关的领域模型!
同一领域模型可以有多种实现模型,用Java、C#、或者任何一种OO语言来实现!
因此,要掌握DDD,关键你先要忘记一切与【实现】相关的技术,否则很容易走火入魔,嘎嘎
我正在实践此设计方法,有可能的话过段时间总结一些心得再与大家分享一下!
学习资源如下:
1 领域驱动设计精简版.pdf
www.infoq.com/cn/minibooks/domain-driven-design...
2 领域驱动设计.软件核心复杂性应对之道.pdf
中文扫描版,175MB,请到CSDN资源下载,或者Google一下
3 Domain-Driven Design Tackling Complexity in the Heart of Software.chm
英文版,4.42MB,请到CSDN资源下载,或者Google一下
刚才写了很多,然后又删了。
DDD是很不错的一种方式,看起来很美,但实际使用未必会顺利。
要使用DDD,个人认为首先要明确领域模型模式与软件构件、SOA架构等模式或者架构风格之间的异同,否则很容易搞岔。
招财猪猪:看了您的领域驱动设计和实现,如果说领域模型包含行为方法。那不是要和下层的数据访问有耦合吗
答:Model处理自己的业务,依赖持久化层,领域层和持久化层是依赖关系,而且是依赖接口,谈不上耦合。只要接口一致,持久化的实现方式可替换。 DDD的讨论很久了,我们用的也比较早,但是面试新员工时发现很多人还是不知道或不甚解,所以就想把这部分内容相对清晰的写一下...
老赵:你们怎么处理复杂的Model关系的持久化啊?遇到这种问题我发现基本都要在Model里让步的,Hibernate这种灵活程度也不足以满足各种问题。
答:我们一般是这么划分的,Model可以负责自身的持久化,复杂Model关系的持久化交给Service层调度。当然,我们还有一套数据字典组件,如果基于数据字典的话,持久化就不用开发人员管理,只写业务,展现、控制和持久化都由数据字典接管。
老赵:数据字典是指什么啊?其实数据字典能处理的也只是通用的,规范的,模式化的持久化方式吧。其他的还是交给Service调度是吧?还有有没有感觉一觉给Service调度就容易变成Transactional Script了啊?
答: 数据字典负责元数据的管理,同时把元数据比如column等映射到展现层,基本上是column-->field-->label/input/control,然后形成视图,比如查询视图、列表视图、编辑视图、工具栏视图,最后形成模板,再形成实际业务。另外服务层主要负责调度领域对象。过于复杂的模型,以至于O/R Mapping处理不了,那就可能是设计上出问题,要么就要Servcie搞定了
老赵:这些倒都可以理解…还有就是你们的dao有哪些接口,又是怎么使用的呢,比如BS是怎么使用的,实体本身是怎么使用的呢。能用文章的例子比如Order的resubmit进行举例吗?
答:BS接管事务,持有DAO,Order的resubmit( IBookStoreDao dao ){ //逻辑判断; //设置订单状态;//设置购买项状态; dao.update(this); } 你懂的。
老赵:喔,原来是这样,懂了。我想到点问题再来问呐。
实践起来就好,那些东西都搞清楚了是需要时间的。
反而用起来,很多东西就清楚啦
学习资源,除了第一个是InfoQ的免费版本,其他两个盗版电子书,就不要推荐了吧。
想学习的话,购买正版书籍,它给你创造的价值绝对会超过书籍本身。
不是,Entity是业务组成的一个单元,它只包含你的部分业务和数据,不持有任何底层设备API的引用。Entity的创建是由Repositories调用底层设备API(DAO)来组装的。
补一句,对于多实体业务的事务,可以交给Repositories去管理DAO来实现。Entity本身不直接面对DAO
或许dao就是你所说的repository,哈哈。另外这种交互也可能通过消息机制去实现
Dao就是Repository,叫法不同而已,我在文章中已经阐述过了
个人觉得组装肯定是实体或者BS去组装的,而repository仅仅是负责持久相关的,也符合单一性原则。个人浅见。
是这样
Dao就是Repository,叫法不同而已,我在文章中已经阐述过了
准确来说是不一样的东西,首先过去的DAO没有DDD中所提到的值对象概念(这个概念,我认为很重要)。
再次,仓储目的是建立对象链,有效利用对象导航,思考对象关系,而数据对象转换已经不是其主要关注点(可以理解为Repository内聚Dao)。
····还有不少细微差别,这些差别来自思维的变化。
一谈到DDD,作为开发人员的我们就会太多的关注在,分几层,用什么技术,什么模式,怎么访问数据库什么的,而忽略了DDD的核心。正如它的名字所说明的那样,DDD要Domain Driven Design! 也就是说,我们要从真实的业务中去寻找和建模领域,再让这个领域模型来驱动我们的程序设计。其实,那些被称之为entity, value object等用代码写成的类,并不是我们的真正的领域模型,它只是领域模型的一种表达而已。
也许有些人在实践中,确实写了不少entity, value object, repository, service,等等这些类,这样来组织代码,但是并没有体会到这样做给你的项目带来多少好处,我想,出现这种情况的大部分原因就是程序员是在脱离了业务的情况下去做DDD。在这种情况下,大家太注于代码实现本身,太观注于数据库,而忘记了领域。所谓的领域模型,从来就没有和领域专家一起商量过,没有得到领域专家的理解和认可。当有了需要变更或新需求的时候,也不是先想领域发生了什么变化,模型发生了什么变化,由此代码应该发生什么变化,而直接想到怎么修改现有代码实现需要的功能。这样时间长了,开发人员和领域专家之间对领域的认识已经发生了不同,领域模型与代码之间不再绑定,领域模型逐不再能让人们沟通方便,不再让人更容易理解程序,最后领域模型就被抛弃了,只剩下entity, value object, service等这些只有程序员才关心的一些名词。这样的DDD实践,必将走向失败。
要想让DDD成功,必须:
1, 与领域专家沟通,学习领域
2, 为领域建模,建出能解决问题,又空易理解,又容易实现的模型
3, 让领域模型与设计和代码绑定,一定是绑定!
4, 需求的变化必须先描述于领域模型的变化,最后才让代码做相应的变化,而不是略过模型,直接为了满足需求而改变代码
如果能做到上面几条,那么框架呀, entity, value object, service,dao什么的,都是程序员在绑定模型与代码之间时用的一些技巧而已,并不是根本。或许到时你可以针对你的领域,发明出task, listener等等符合你的领域的一类模型。
我感觉playframework框架就是用的DDD模式。
您说的很精彩!
DDD的第一个要点我认为是通过模型来尽最大可能的理解所要面对的domain 本身--crunch knowledge. 这个从我自己来说真的起到了很重要的作用。在相互之间的逻辑关系理不清楚的时候,往往就意味着你还没有能力准确的用计算机来处理这个需求。
Few people can do it well,and It's very hard to teach!
我关注和研究DDD已经有6、7年了。
刚开始, 觉得第一要务是将“实现技术”从领域模型中剥离出去,例如持久化、通讯、日志、事务等等。为此我还写过一篇关于分离领域模型的小论文。在Spring和Hibernate的早期,还停留在反EJB的阶段,基本上不支持富领域模型,对贫血模型却是支持良好,也催生了大量习惯使用贫血模型的程序员。自spring2.5之后,剥离“实现技术”在java领域已经不是太大问题。
中间阶段,和javaeye中很多人一样,纠结于充血模型和胀血模型的优劣。两者最核心的问题在于业务对象与业务对象之间的“黏合代码”的职责分配。 充血模型认为,黏合代码是service的职责, 而涨血模型认为,黏合代码是聚合根的职责。 涨血模型因此在业务对象内引入持久层接口,以增加耦合性为代价,获得更大范围(包括黏合代码)的复用。
经过多年的实践,我发现,处理不好黏合代码是应用DDD最常见的障碍。就像楼主所说“因为总会有些业务逻辑,既不属于这个领域对象,也不属于那个,那这部分业务由谁来处理呢?”我总结有三种办法:
1、事物脚本: 在service层下加一个domain子层,叫domain service,专门放一些简单的,但需要跨service复用的黏合代码,domain service一般以领域的一个聚合为范围。domain service复用的是方法或者函数,没有状态。
2、Action: 将这段黏合代码放到一个service新建的action对象里,然后由对象来完成协调多个领域对象、收集中间结果、处理最后结果的工作。service层的伪码就变成:
XX xx = repo.findXX(...);
YY yy = repo.findYY(...);
Action action = new Action(xx, yy);
action.execute();
repo.saveXX(action.getChangedXX());
repo.saveYY(action.getChangedYY());
service层的代码没有太多分支和判断,十分清晰。action内部可以在整个对象范围内复用状态,而不必像domain service那样靠参数传递,并且可以充分利用代理,将内部一些可复用的黏合代码代理给别的对象,例如策略对象簇。
3、Domain Object:当Action含义很特殊时,不妨就用Action的原意(动作,行动)作为名字。但是,当Action的含义在领域内很通用的时候, 就应该将名字改为领域内的术语,促进对这个新概念的理解。 有些人会称之为Value Object。鉴于Value Object的理解有很多流派,我更愿意称之为non-Entity Domain Object. 当然,Action转变来的对象只是non-Entity DO的一种,还有其他的来源。
4、涨血的聚合根: 聚合根是学习DDD的兄弟们耳熟能详的概念了, 不多说, 列代码供比较:
service:
----------------------------
//service变得非常薄,所有黏合代码都被复用了。但service因此失去了对持久层变化的敏感,
//有时候聚合划分不当,会重复保存同一个对象。
xxyyRoot = xxyyRepo.findXXYYRoot(...);
xxyyRoot.doSomething();
xxyyRoot.save();
xxyyRepo.findXXYYRoot(...):
---------------------------
//引入了对持久层的接口的依赖,如依赖过深,设计不好,测试将会变得困难。
xxyyRoot = ....;
xxyyRoot.setRepo(this);
XXYYRoot.doSomething():
--------------------------
...
// now I need yy
// when unit test, need mock repo, which is unstable dependency. so unit test may be unstable either.
yy = this.repo.findYY(...);
yy.doA();
xx.doWith(yy);
XXYYRoot.save():
--------------------------
repo.save(xx);
repo.save(yy);
我的经验是,当黏合代码涉及特别狗血的逻辑,例如根据循环内部的判断决定是否读取仓储,这时从service这层协调非常绕,要是采用胀血模型会节省很大的代码量,而且表达清晰。 除非如此,我尽量不考虑涨血模型。
我也比较喜欢用不依赖于仓储的聚合根,这会比较清晰。
到了最近两年,我发现DDD的精髓在于建模,建模的精髓在于命名(隐喻)。而DDD的另外一个核心是围绕模型的需求管理过程,这也是一个难点,正在努力实践中。
更正与补充:
Action与non-Entity Domain Object的形式是相似的,算一类办法, 因此仍然算3种办法。
我听说有些流派把类似Action的对象当成Context(上下文), 并且将一些BO根据在不同的上下文的角色分为若干个子接口,上下文只使用接口作为引用类型,进一步限制了BO的可见性,增强了复用的可能。 听起来是不错,但还没有时间研究。哪些朋友有兴趣,不妨一起来研究一下。。
现在我写代码最舒适的顺序是广度优先,即留着编译错误不管,先把Service方法写完,尽量多代理给bo,少写实现,避免第二层if或者循环。 这样会逼着我去思考每一块逻辑的职责分配。
service写完了,补上各种没写的方法的skaleton,测试,提交。 然后在依次在稍小的范围内广度优先去实现BO或者Repo的某个方法,这时候就脑子的上下文就切换到这个小的职责范围内,忘掉外面的所有逻辑。
在网上书店的例子里,order是要调用BookStoreDao来存储自己吗?那BookStoreDao不用依赖Order吗?
同感。
个人认为DDD的本质就是你对你要服务的业务领域的认知。只有你对业务领域的知识有了充分的学习后,才能将领域内的知识转化为一个个类或者说是对象。而在这种转化的过程中不光你需求充足的领域知识,还要有比较好面向对象的思维方式。一切的一切离不开最基本的面向对象的思维。有了这种思维后你会发现你的设计与DDD是那么的相近。
同意!
Order.submit(IOrderDao dao)
订单模型自己是有了提交的方法,实际上是交给数据反问对象处理的。(认为一个类应该在概念上尽量简单,职责单一)
IOrderDao有
+FindById()
+SaveOrUpdate()
+SelectAll()
那我是否可以这样用Order order = new Order(); order.FindById(xxx);内部代码是否包含 this = x(x,代表从持久层获取的数据),order.FindById是没有返回值的。
如果是SaveOrderUpdate这样写倒是好理解,FindById感觉就是通过自己找别人(同一类型的),当然可以做成静态的。
我认为数据模型,自己的方法不应该有持久层交互的能力,允许修改自身数据,但不能持久。
一个类应该在概念上尽量简单,职责单一,导致更加喜欢贫血的领域模型。
在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了Java SE1.6中对于锁的性能优化,以及锁的存储结构及升级过程。
本次分享将首先介绍现代富文本编辑器的组成和实现,然后结合UEditor的开发过程,与参会者分享UEditor在设计和实现的过程中,所涉及到的核心功能的细节实现。
本次演讲视频录制于百度技术沙龙。
我们所开发的应用程序大多都需要提供一个图形用户界面(GUI)。关于GUI应用的架构设计,已经有了Form & Control、MVC,、MVP、 Passive View等多种模式。模式可以帮助我们建立优雅的架构,但前提是弄清楚模式的应用场景。弄清楚GUI应用面临的设计上的问题,有助于我们正确的挑选设计方案。
MongoDB是一种非常易用的NoSQL方案,Brian C. Dilley在这篇文章里介绍了MongoDB的优劣势,并介绍了MJORM项目。MJORM用于MongoDB,是一个没有注解的Java ORM库。
随着网络基础设施的逐步成熟,从RPC进化到Web Service,并在业界开始普遍推行SOA,再到后来的RESTful平台以及云计算中的PaaS与SaaS概念的推广,分布式架构在企业应用中开始呈现出不同的风貌,然而殊途同归,这些分布式架构的目标仍然是希望回到建造巴别塔的时代,系统之间的交流不再为不同语言与平台的隔阂而产生障碍。
精益软件开发方法因其对市场和交付的重视和在各种场景下体现出的适应能力正在获得广泛的关注。特别是在精益创业(Lean Startup)渐渐兴起和技术日新月异的今天,其"极端"的思想也变得越来越必要和可行。 InfoQ就此主题对他做了深入的采访。
33 条回复
关注此讨论 回复