- 浏览: 190614 次
- 性别:
- 来自: 北京
最新评论
-
bzhao:
开启了一个很牛逼的话题!
提高程序员的准入门槛? -
迷人阳光love:
不知两年多了,lz整理的从问题出发的模式是否还在??很是渴望得 ...
学习模式,不如先了解问题 -
迷人阳光love:
lz说到了我的心坎里,这是您10年发的文章,现在 也没找到一个 ...
学习模式,不如先了解问题 -
toafu:
我的理解是,持续集成和交付也解决不了人的问题。
为什么我的敏捷项目有如此多的问题? -
liaofeng_xiao:
《不可承受的生命之轻》 ,真没看出太多内容~
近期看的书和电影
距离上次发帖讨论领域模型,已经有半年了。这么久没有炒,估计饭又冷了。我再来炒炒领域模型这锅冷饭吧。且不着急点回退按钮,最近领域驱动设计社区在Greg Young同学的带领下有不少新的发展。保证这一次不会是重复贫血充血的老调调。
上回我们说到领域模型实践中的两个困境。一个是框架带来的Entity无法注入的问题。另外一个是Java无Mixin带来的类膨胀的问题。没有看过上文的同学请先回去复习一下:http://www.iteye.com/topic/281289。今天我们就不谈其他,就这两点来谈一谈吧。
类膨胀
这是一个只有你真正把逻辑都放到领域模型了才会遇到的高级问题。当我们把逻辑不断地从Service层抽到Domain层的时候,一些核心的Entity类往往会变得巨大无比。直觉告诉我们,这肯定违反了Single Responsibility Principle(所谓SRP)。那么我们怎么才能解决这个问题呢?
Mixin
当时我发帖的时候,觉得解决这个问题的方向是Mixin。Ruby有Module,C#有Extension Method,Java缺乏语言原生的支持,所以有qi4j这样的项目(我同意,qi4j的实现确实是有点那个。。。)。但是经过一段时间来的学习和思考,觉得Mixin只是一种头痛医头脚痛医脚的办法,根本没有从根本上解决问题。
使用Mixin只是把行为的定义分开了,分散到了几个源文件去定义了。但是逻辑上行为仍然是在那个Entity上的。而且运行时,行为也是在那个Entity上的。从代码阅读的角度来说,确实一次看到的源代码行数是变少了,但是从整体理解的角度来说,读懂一个Entity的复杂度并没有降低。从某种角度来说,Mixin就像是从前的宏(Macro),都是神奇般地给你的代码加点料。
职责委托
发生膨胀的类往往是一些Aggregate Root,把聚合了很多子Entity。比如说ShoppingBasket聚合了Package,而Package聚合了Item。很多时候,我们可以把职责委托给这些子Entity。比如Item可以计算自己的价格,然后Package再把Item的价格加总,然后Basket再把Package的价格加总。通过把职责委托出去,Aggregate Root更多的是一个Mediator,协调各方面来完成任务,而不是事事都必须亲历亲为。
要把职责委托出去就必须让这些职责有一些接收方。如果之前productPackages只是一个List,这个时候就可以创建一个自定义的ProductPackages类来持有相关的逻辑。如果之前几个field联系紧密(比如一个叫fromDate,一个叫toDate),就可以把这些联系紧密的field打包成一个类把相关的职责委托给它。
当我们把职责委托出去之后,Aggregate Root在某些场合只是Middle Man。比如
如果对这些纯委托的方法感觉不爽,不妨提供getProductPackages方法让外边直接调用findByName好了。
Bounded Context
一般来说,通过有效的职责委托,完全可以避免一个Entity的尺寸过大。但是这必须建立在你所写的系统的职责单一的基础之上。也就是说单个类的SRP必须建立里在系统的SRP之上。如果像这位同学说的那样:
我们的系统有很多模块组成, 各模块基本上通过数据库来共享信息。
主要的模块大致有: 核心系统(非web), 网站、 bbs、 网站后台,核心系统后台,BI, 推广员等等
原来的打算是写个rich domain model供各模块来使用,以便代码重用减轻个模块开发的工作量
一个简单的例子, User 原有 changePassword, getFriends, addFriend ... 等等方法撇开配置以及获取User对象的复杂性不谈, 实际开发中发现, 这些东西重用的地方太少了,对网站来说很好的rich domain model, 在网站后台里面就麻烦,很多方法在那里根本就是对后台开发人员的干扰,而很多方法对核心系统、BI等等根本就毫无用处。
那么他所说的User是无论如何做不到SRP的。用Eric Evan的术语就是我们在处理不同的Bounded Context。所以对于之前我画的那个图,现在就有不同理解了:
当时我的理解是一个类在不同的Context下有不同的职责(Role),所以需要实现不同的Interface代表这些Role。于是乎类就是封装一组数据在不同的Context下的行为。又由于系统往往有很多的context,而类所封装的数据又要被这些context给共享(比如User),所以一个类就无可避免地要变得非常的膨胀。
我犯了两个错误。首先Interface代表的Role不是Bounded Context这个级别的。让一个User去实现ForumUser接口,NewsUser接口,SnsUser接口从而被不同模块共享是不现实的,也没有人去这么做。其次,在边界划分良好的情况下,一个系统内应该不会有太多的context,如果一个系统做了很多不同的事情,那是在系统规划设计上就出了问题,而这样的问题比面向对象设计一个类的问题要大得多。
所以,从根本上避免类膨胀,就必须首先避免系统承担的职责的膨胀。理想情况下一个团队负责一个模块/系统,只处理一个Bounded Context。然后跨Bounded Context的集成不是靠一个对象封装一组数据实现不同系统的接口来实现(那简直是开玩笑),而是靠Context Mapping来实现。具体的Mapping的措施,在下文中讨论。
Entity依赖Service
之前我也讨论过,很多朋友也讨论过如何用各种各样tricky的技术实现对Entity的依赖注入。但是,Entity为什么会有这些依赖?没有这些依赖存在的话,Entity就无法完成自己的职责,我们就必须把逻辑写到所谓的Application Service之中吗?
总结起来,Service依赖有三种情况:
没有,就很慢
理论上来说,Domain Model就是一个大的对象图。对象之间可以通过之间的关系彼此获得。通过Navigate对象图,我们可以从一个节点到达了任意地方。但是由于效率的原因,很多对象之间的关联必须人为打断。比如说你是一个User,用户可以发信。如果User有一个sentEmails的属性,我们去访问这个属性的成员的时候就可能触发成千上万条SQL。所以从实践中,像User这样的长生命周期对象是不会有链接到Email这样的短生命周期的对象的。
一旦Domain Model不再是一个完整联通的对象图,我们的Entity就无法通过Navigation拿到和自己协同工作的对象了。所以,往往Entity需要一些DAO或者Repository来拿到自己的关联对象。这样的优化我们称之为Replace field with query。解决办法在以前贫血不贫血的讨论中已经有反复提及了:http://www.iteye.com/topic/191261。唯一欠缺的是具有Production Quality的实现方案而已。折衷的措施是把Repository当参数传递进去,或者使用Query Object模式。或者干脆就放到Application Service中做好了。
没有,数据就拿不到,服务拿不到
这种情况是一些业务操作需要另外一个系统提供的数据,比如说是一个提供pricing的web service。如果没有这个web service,我们就只能把计算总价的职责从domain model中拿出来,因为它没有办法很容易的拿到一个web service的引用。
再比如说,验证一个ShoppingBasket是不是合法,可能需要规则引擎中定义的一些规则(规则可能是业务专家用Excel定义的)。这样basket就不能validate自己了,这样我们也不能让basket告诉我们是不是可以checkout了。
没有,数据就发布不出去
另外一种情况是一些业务操作要把一些数据发出去。比如说publication.distribute需要用ftp把元数据和附件传给一些第三方系统。
又比如,你给一个meeting添加一个note需要给meeting的参与者发一些alert,告诉他们有人更新了meeting的note了。如果这种alert不是系统的内,比如是email或者是MSN的消息,那么就需要在domain model里做一些向外发布数据操作。
Bounded Context Mapping
第一种情况是对象图存取的问题,属于另外一个范畴的问题。不过第一种情况是大部分人想要给Entity注入Service的动因。但是这种情况下,注入不是一个好主意。理想的情况应该是Infrastructure(Hibernate这一层的东西)能够提供更好的Replace field with query的支持。
第二三种情况是因为Bounded Context A对Bounded Context B需要做Context Mapping。Mapping可以是从A到B的(发),也可以是从B到A的(取)。根据Mapping发生的时机又分为预先取,实时取(同步),实时发(同步),实时发(异步),事后发。
预先取
这种情况适用于另外一个Bounded Context的数据的实时性不强,而且尺寸不大。可以预先获取并缓存。
实时取(同步)
这种情况是需要Domain Service的唯一情况。Eric Evan的书中并没有详细说什么情况下需要Domain Service。很多同学都把Domain Service和Application Service搞混了。Domain Service存在,必须是Bounded Context A对于Bounded Context B有实时的同步的获取服务的要求。Shipping那个例子里的ScheuleService,Online Shopping的PricingService,或者依赖于某规则引擎都适用于这种情况。
实时发(同步)
一般来说都不需要是同步的,因为只是发。推荐把同步发改为异步发。不然也需要提供一个Domain Service来做同步的发。
实时发(异步)
这就是Greg Young同学非常津津乐道的Distributed DDD的基本原理了。如果Bounded Context A需要给Bounded Context B发消息,可以在Bounded Context A中建立一个List代表Bounded Context B的InBox。我们只需要把以往的DTO改名为Message然后往队列里一扔就代表我们给B的InBox发了一封信了。然后由Infrastructure取监听那个List取做真正的跨进程通信,可能是调用某个web service,也可能是往message queue发消息。
事后发
如果实时性不强的话。上面提到的那个List都不需要是实时监听的。只需要在业务操作完成之后检查一下List是不是非空。如果有东西,就发出去。
结论
上篇帖子提出的两个阻碍领域模型应用的因素按照分析可以列为:
对于类膨胀,我们一方面要把职责委托出去,另外一方面是关注应用程序本身(而不仅仅是类)的职责是不是太多。
依旧期待框架提供更好的Replace field with query的能力。
Entity引用Domain Service的情况不多。如果有,可以考虑用参数传进去。注入也可以考虑,如果不麻烦的话。
Entity做Messaging一般人都用不着。如果需要,实现起来也不难。
上回我们说到领域模型实践中的两个困境。一个是框架带来的Entity无法注入的问题。另外一个是Java无Mixin带来的类膨胀的问题。没有看过上文的同学请先回去复习一下:http://www.iteye.com/topic/281289。今天我们就不谈其他,就这两点来谈一谈吧。
类膨胀
这是一个只有你真正把逻辑都放到领域模型了才会遇到的高级问题。当我们把逻辑不断地从Service层抽到Domain层的时候,一些核心的Entity类往往会变得巨大无比。直觉告诉我们,这肯定违反了Single Responsibility Principle(所谓SRP)。那么我们怎么才能解决这个问题呢?
Mixin
当时我发帖的时候,觉得解决这个问题的方向是Mixin。Ruby有Module,C#有Extension Method,Java缺乏语言原生的支持,所以有qi4j这样的项目(我同意,qi4j的实现确实是有点那个。。。)。但是经过一段时间来的学习和思考,觉得Mixin只是一种头痛医头脚痛医脚的办法,根本没有从根本上解决问题。
使用Mixin只是把行为的定义分开了,分散到了几个源文件去定义了。但是逻辑上行为仍然是在那个Entity上的。而且运行时,行为也是在那个Entity上的。从代码阅读的角度来说,确实一次看到的源代码行数是变少了,但是从整体理解的角度来说,读懂一个Entity的复杂度并没有降低。从某种角度来说,Mixin就像是从前的宏(Macro),都是神奇般地给你的代码加点料。
职责委托
发生膨胀的类往往是一些Aggregate Root,把聚合了很多子Entity。比如说ShoppingBasket聚合了Package,而Package聚合了Item。很多时候,我们可以把职责委托给这些子Entity。比如Item可以计算自己的价格,然后Package再把Item的价格加总,然后Basket再把Package的价格加总。通过把职责委托出去,Aggregate Root更多的是一个Mediator,协调各方面来完成任务,而不是事事都必须亲历亲为。
要把职责委托出去就必须让这些职责有一些接收方。如果之前productPackages只是一个List,这个时候就可以创建一个自定义的ProductPackages类来持有相关的逻辑。如果之前几个field联系紧密(比如一个叫fromDate,一个叫toDate),就可以把这些联系紧密的field打包成一个类把相关的职责委托给它。
当我们把职责委托出去之后,Aggregate Root在某些场合只是Middle Man。比如
ProductPackage findByName(String name) { return productPackages.findByName(name); }
如果对这些纯委托的方法感觉不爽,不妨提供getProductPackages方法让外边直接调用findByName好了。
Bounded Context
一般来说,通过有效的职责委托,完全可以避免一个Entity的尺寸过大。但是这必须建立在你所写的系统的职责单一的基础之上。也就是说单个类的SRP必须建立里在系统的SRP之上。如果像这位同学说的那样:
coolnight 写道
我们的系统有很多模块组成, 各模块基本上通过数据库来共享信息。
主要的模块大致有: 核心系统(非web), 网站、 bbs、 网站后台,核心系统后台,BI, 推广员等等
原来的打算是写个rich domain model供各模块来使用,以便代码重用减轻个模块开发的工作量
一个简单的例子, User 原有 changePassword, getFriends, addFriend ... 等等方法撇开配置以及获取User对象的复杂性不谈, 实际开发中发现, 这些东西重用的地方太少了,对网站来说很好的rich domain model, 在网站后台里面就麻烦,很多方法在那里根本就是对后台开发人员的干扰,而很多方法对核心系统、BI等等根本就毫无用处。
那么他所说的User是无论如何做不到SRP的。用Eric Evan的术语就是我们在处理不同的Bounded Context。所以对于之前我画的那个图,现在就有不同理解了:
当时我的理解是一个类在不同的Context下有不同的职责(Role),所以需要实现不同的Interface代表这些Role。于是乎类就是封装一组数据在不同的Context下的行为。又由于系统往往有很多的context,而类所封装的数据又要被这些context给共享(比如User),所以一个类就无可避免地要变得非常的膨胀。
我犯了两个错误。首先Interface代表的Role不是Bounded Context这个级别的。让一个User去实现ForumUser接口,NewsUser接口,SnsUser接口从而被不同模块共享是不现实的,也没有人去这么做。其次,在边界划分良好的情况下,一个系统内应该不会有太多的context,如果一个系统做了很多不同的事情,那是在系统规划设计上就出了问题,而这样的问题比面向对象设计一个类的问题要大得多。
所以,从根本上避免类膨胀,就必须首先避免系统承担的职责的膨胀。理想情况下一个团队负责一个模块/系统,只处理一个Bounded Context。然后跨Bounded Context的集成不是靠一个对象封装一组数据实现不同系统的接口来实现(那简直是开玩笑),而是靠Context Mapping来实现。具体的Mapping的措施,在下文中讨论。
Entity依赖Service
之前我也讨论过,很多朋友也讨论过如何用各种各样tricky的技术实现对Entity的依赖注入。但是,Entity为什么会有这些依赖?没有这些依赖存在的话,Entity就无法完成自己的职责,我们就必须把逻辑写到所谓的Application Service之中吗?
总结起来,Service依赖有三种情况:
没有,就很慢
理论上来说,Domain Model就是一个大的对象图。对象之间可以通过之间的关系彼此获得。通过Navigate对象图,我们可以从一个节点到达了任意地方。但是由于效率的原因,很多对象之间的关联必须人为打断。比如说你是一个User,用户可以发信。如果User有一个sentEmails的属性,我们去访问这个属性的成员的时候就可能触发成千上万条SQL。所以从实践中,像User这样的长生命周期对象是不会有链接到Email这样的短生命周期的对象的。
一旦Domain Model不再是一个完整联通的对象图,我们的Entity就无法通过Navigation拿到和自己协同工作的对象了。所以,往往Entity需要一些DAO或者Repository来拿到自己的关联对象。这样的优化我们称之为Replace field with query。解决办法在以前贫血不贫血的讨论中已经有反复提及了:http://www.iteye.com/topic/191261。唯一欠缺的是具有Production Quality的实现方案而已。折衷的措施是把Repository当参数传递进去,或者使用Query Object模式。或者干脆就放到Application Service中做好了。
没有,数据就拿不到,服务拿不到
这种情况是一些业务操作需要另外一个系统提供的数据,比如说是一个提供pricing的web service。如果没有这个web service,我们就只能把计算总价的职责从domain model中拿出来,因为它没有办法很容易的拿到一个web service的引用。
再比如说,验证一个ShoppingBasket是不是合法,可能需要规则引擎中定义的一些规则(规则可能是业务专家用Excel定义的)。这样basket就不能validate自己了,这样我们也不能让basket告诉我们是不是可以checkout了。
没有,数据就发布不出去
另外一种情况是一些业务操作要把一些数据发出去。比如说publication.distribute需要用ftp把元数据和附件传给一些第三方系统。
又比如,你给一个meeting添加一个note需要给meeting的参与者发一些alert,告诉他们有人更新了meeting的note了。如果这种alert不是系统的内,比如是email或者是MSN的消息,那么就需要在domain model里做一些向外发布数据操作。
Bounded Context Mapping
第一种情况是对象图存取的问题,属于另外一个范畴的问题。不过第一种情况是大部分人想要给Entity注入Service的动因。但是这种情况下,注入不是一个好主意。理想的情况应该是Infrastructure(Hibernate这一层的东西)能够提供更好的Replace field with query的支持。
第二三种情况是因为Bounded Context A对Bounded Context B需要做Context Mapping。Mapping可以是从A到B的(发),也可以是从B到A的(取)。根据Mapping发生的时机又分为预先取,实时取(同步),实时发(同步),实时发(异步),事后发。
预先取
这种情况适用于另外一个Bounded Context的数据的实时性不强,而且尺寸不大。可以预先获取并缓存。
实时取(同步)
这种情况是需要Domain Service的唯一情况。Eric Evan的书中并没有详细说什么情况下需要Domain Service。很多同学都把Domain Service和Application Service搞混了。Domain Service存在,必须是Bounded Context A对于Bounded Context B有实时的同步的获取服务的要求。Shipping那个例子里的ScheuleService,Online Shopping的PricingService,或者依赖于某规则引擎都适用于这种情况。
实时发(同步)
一般来说都不需要是同步的,因为只是发。推荐把同步发改为异步发。不然也需要提供一个Domain Service来做同步的发。
实时发(异步)
这就是Greg Young同学非常津津乐道的Distributed DDD的基本原理了。如果Bounded Context A需要给Bounded Context B发消息,可以在Bounded Context A中建立一个List代表Bounded Context B的InBox。我们只需要把以往的DTO改名为Message然后往队列里一扔就代表我们给B的InBox发了一封信了。然后由Infrastructure取监听那个List取做真正的跨进程通信,可能是调用某个web service,也可能是往message queue发消息。
事后发
如果实时性不强的话。上面提到的那个List都不需要是实时监听的。只需要在业务操作完成之后检查一下List是不是非空。如果有东西,就发出去。
结论
上篇帖子提出的两个阻碍领域模型应用的因素按照分析可以列为:
- 类膨胀
- 框架没有提供Replace field with query的能力
- Entity引用Domain Service
- Entity做Messaging
对于类膨胀,我们一方面要把职责委托出去,另外一方面是关注应用程序本身(而不仅仅是类)的职责是不是太多。
依旧期待框架提供更好的Replace field with query的能力。
Entity引用Domain Service的情况不多。如果有,可以考虑用参数传进去。注入也可以考虑,如果不麻烦的话。
Entity做Messaging一般人都用不着。如果需要,实现起来也不难。
评论
4 楼
testoktest2
2009-08-06
为什么要:让一个User去实现ForumUser接口,NewsUser接口,SnsUser?
不能 ForumUser类/NewsUser/SnsUser 都继承 User类吗
f/n/s 有自己不同的方法
listMessage()
listNews()
changeNews()
deleteNews()
怎么管理用户
有adminUser类,有方法
deleteUser/changeUserPassword/createUser
被管理的user就是 User类,有啥Password属性
那有没有listNews()方法,肯定没有马,被管理的user 当前根本不是NewsUser
如果要看被管理的user,一共发了多少新闻,有个userRole属性,
还有user.userRole.NewsUser
之后就是
user.userRole.NewsUser.NewsCount()
user.userRole.NewsUser.listNews()
这样难道不行?
不能 ForumUser类/NewsUser/SnsUser 都继承 User类吗
f/n/s 有自己不同的方法
listMessage()
listNews()
changeNews()
deleteNews()
怎么管理用户
有adminUser类,有方法
deleteUser/changeUserPassword/createUser
被管理的user就是 User类,有啥Password属性
那有没有listNews()方法,肯定没有马,被管理的user 当前根本不是NewsUser
如果要看被管理的user,一共发了多少新闻,有个userRole属性,
还有user.userRole.NewsUser
之后就是
user.userRole.NewsUser.NewsCount()
user.userRole.NewsUser.listNews()
这样难道不行?
3 楼
raymond2006k
2009-06-17
楼上说的没错, 领域建模仍要保持简单的原则。
我们实践中,可能早上听了一堂《领域建模》的培训,觉得无比优雅,“就应该这样”;可是下午因为项目赶进度,就随意添加属性和方法,而违背了领域建模的原则。 更深的原因确实是 framework 没能提供一个符合domain思想的建模规范和约束,例如 Hibernate 侧重ORM,它的 Domain Modeling 还是以 Data Model 为中心的领域建模,而没有上升到行为和事件(虽然它也支持Event,但是是数据级的)。
当然,类膨胀是要势待解决的问题。遵守domain思想下,设计思路要有所突破,怎样优雅的委托出去,怎样做 context mapping等。
我们实践中,可能早上听了一堂《领域建模》的培训,觉得无比优雅,“就应该这样”;可是下午因为项目赶进度,就随意添加属性和方法,而违背了领域建模的原则。 更深的原因确实是 framework 没能提供一个符合domain思想的建模规范和约束,例如 Hibernate 侧重ORM,它的 Domain Modeling 还是以 Data Model 为中心的领域建模,而没有上升到行为和事件(虽然它也支持Event,但是是数据级的)。
当然,类膨胀是要势待解决的问题。遵守domain思想下,设计思路要有所突破,怎样优雅的委托出去,怎样做 context mapping等。
2 楼
firebody
2009-06-03
观点都是正确。
但是我觉得这么多正确的观点,反而忽略了一个最基本的观点:简单,美妙的代码需要简单、美妙的设计作为底层支撑。
设计体现在 领域模型的设计,整体架构的设计这些基本方面。
很赞同某位软件大师说过的话,具体什么话忘了,大概意思是这么说: 怎么定义这个代码是简单、美妙的呢? 你只需要看它是否自始至终都保持一个核心设计理念。 如果他能做到这点,那么他就是简单美妙的。
所以,很有意思的是,如果你发现你自己写的代码膨胀了, 立即重构,重构有两个层次: 代码级别的重构,设计级别的重构。
前者大家经常做,后者大家也别忘了要经常做,后者的原则就是一点: 保持简单美妙的核心设计理念,贯穿在你所有代码里面。
做到这点了,也不需要像楼主这么费心费力了,呵呵,开玩笑。
但是我觉得这么多正确的观点,反而忽略了一个最基本的观点:简单,美妙的代码需要简单、美妙的设计作为底层支撑。
设计体现在 领域模型的设计,整体架构的设计这些基本方面。
很赞同某位软件大师说过的话,具体什么话忘了,大概意思是这么说: 怎么定义这个代码是简单、美妙的呢? 你只需要看它是否自始至终都保持一个核心设计理念。 如果他能做到这点,那么他就是简单美妙的。
所以,很有意思的是,如果你发现你自己写的代码膨胀了, 立即重构,重构有两个层次: 代码级别的重构,设计级别的重构。
前者大家经常做,后者大家也别忘了要经常做,后者的原则就是一点: 保持简单美妙的核心设计理念,贯穿在你所有代码里面。
做到这点了,也不需要像楼主这么费心费力了,呵呵,开玩笑。
1 楼
yimlin
2009-06-03
搬个板凳先
发表评论
-
Guice这高级货
2009-06-15 15:17 6888Guice在大部分时间都是很方便的,简单易用。Guice和Sp ... -
让AnnotationConfiguration支持自定义UserCollectionType
2008-12-09 17:45 2754在Hibernate的Jira上,这个两个issue已经放了很 ... -
领域模型的价值与困境
2008-11-27 23:23 3830很久以前大家就关于这个方面有很多讨论了。前两天我又挖了一个坑来 ... -
你所不知道的CommandBar
2008-10-29 08:40 2877Office能够让你写插件。2 ... -
关于Estimation的随笔
2008-10-27 09:04 1113Estimation有很多流派。 从数字的选择上来看:有的人喜 ... -
Domain Model - The Theory, The Reality, The Dream
2008-08-10 21:25 1248梦想照进现实 -
关于estimation的闲言碎语
2008-07-11 09:06 1453estimation只是一个开始,不是结束.好的estim ... -
let's placeBid
2008-05-12 10:11 1478这个例子很老啦,在之 ... -
贫血的Domain Model
2008-05-09 00:18 5170好老的话题啦。拿出来炒炒冷饭。各位见谅。 —————————— ... -
图形界面自动化测试
2008-05-04 22:16 2004Windows Win32 API (pywinauto, a ... -
the paint points of xaml
2008-01-16 08:56 1434Pain Point 1: XAML always creat ... -
lessons we have learnt about office integration
2008-01-16 08:54 1394Lesson 1: trust it Everything ... -
Outlook MAPIOBJECT
2008-01-09 18:06 2039Outlook的对象模型中,很多对象都有一个MAPIOBJEC ... -
.NET Remoting Callback
2007-10-12 20:42 2198有三个主要的障碍: 1、服务器解析不到客户端的assembly ... -
企业应用开发者使用WPF的三个理由
2007-05-16 23:02 5695让控件更灵活的Data Template ... -
用UIAutomation做验收测试
2007-05-16 22:19 4511这是被测的应用程序: 应用.NET 3.0提供的UIA ... -
mock框架搞什么搞?
2007-05-11 11:11 13433今天早上一时兴起,去网上下载下来JMock,EasyMock最 ... -
主动重构 => 被动重构
2007-05-10 16:34 1950引言 最近杂七杂八地思考了不少东西。但是很惊异地发现这三三两 ... -
我的酒窝.NET
2007-04-30 16:59 2724ajoo同学的酒窝有.NET版本啦! 项目主页: http: ... -
Naive Container 发布1.0版本
2007-04-29 17:50 2556二进制文件和源代码可以从这里下载到: http://naive ...
相关推荐
本研究旨在确定在中国大肠癌治疗中应用的患者导航模型的现状和困境。 方法:采用文献计量法分析从Web of Science数据库检索的有关患者导航模型在结直肠癌治疗中的应用的已发表文章。 统计数据是使用书目项目共现...
因此,解决这一困境的方法是为教师提供一个有效的模块,以发展学生的道德推理和批判性思维。 这项研究的目的是:1)描述ADDIE模型在道德教育(PIME)模块中发展哲学探究方法的用途,以及2)识别模块内容的有效性。 ...
简要介绍社会困境的涵义,详细阐述博弈决策的理性选择理论、认知转换理论和生物进化理论,并且从认知控制、社会认知...未来研究应力求突破先前理论模型的不足,深入考察个体合作行为的神经机制,并向实际应用领域发展.
随着对它研究的深入,这个问题已经作为一种模型被应用到现实社会的很多领域:经济学、社会学、商务谈判。这就提出了一个问题:如何有效地求解囚犯困境问题。利用遗传算法,对囚犯困境问题进行了求解。并且根据所提的...
困境的勘探/开发要求并强调相关的需求,首先是从获得的竞争优势中大量使用投入和专业知识,其次,公司需要在新领域保持合乎逻辑和探索性的创造力。 根据与实施租车公司相关的组织创新的分析,似乎:-组织学习是按...
同样,外商投资企业在外贸领域和经济中的作用是宏观经济舞台上的亮点之一。 然而,沟通问题困扰着中西业务,事实上它们困扰着大多数跨文化合资企业。 在中国的案例中,根源在于商业情境中西方普世价值观与中国特殊...
一对计算机科学家最近开发了一种巧妙的方法来衡量世界范围内的互联网过滤和审查,包括... 我们希望我们提出的问题对在自己的工作中面临类似困境的研究人员以及技术学科和法律和哲学等其他领域的研究伦理学学生有用。
2)从消费者网络构建的属性可以改进通过采用可能性对目标客户进行排名的模型,以及 3)观察网络允许公司瞄准那些可能会陷入困境的新客户,因为他们不会仅仅基于公司用于营销的传统属性集。 我们最后讨论了该领域...
软件工程领域中编程语言研究的经验和实践可以为我们摆脱困境提供一些启发。 本文旨在从软件工程的角度对AOP进行调查,包括AOP的研究历史以及有关面向代理的编程概念和模型,语言,CASE工具和运行方式的最新研究。 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用 8.7.2 使用 8.7.3 使用 8.7.4 使用 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 8.9 练习 第9章 违例差错...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...
8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 ...