<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_致力于面向对象、仿生物领域建模技术方面的研究</title><subtitle type="text">要学会站在巨人的肩膀上让自己成长。QQ：94388050</subtitle><id>http://feed.cnblogs.com/blog/u/17223/rss</id><updated>2012-01-30T16:06:29Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/17223/rss"/><entry><id>http://www.cnblogs.com/netfocus/archive/2012/01/31/2332520.html</id><title type="text">CQRS NOTES</title><summary type="text">CQRS NOTES:Command: A command represents what user want to do, user can send a command to the system to ask the system what he or she wants to do; command doesn&amp;#39;t have result. The client can make of the query data store when validating commands. On the server side, the only reason that such a co</summary><published>2012-01-30T16:06:00Z</published><updated>2012-01-30T16:06:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2012/01/31/2332520.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2012/01/31/2332520.html"/><content type="html">&lt;div&gt;&lt;div&gt;CQRS NOTES:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Command: A command represents what user want to do, user can send a command to the system to ask the system what he or she wants to do; command doesn't have result. The client can make of the query data store when validating commands. On the server side, the only reason that such a command would fail would be due to concurrency. As such, validation can be performed on the client, checking that all fields required for that command are there, number and date ranges are OK, that kind of thing. The server would still validate all commands that arrive, not trusting clients to do the validation. What we see is that in this model, commands don&amp;#8217;t need to be processed immediately &amp;#8211; they can be queued. Another part is the issue of failed message processing due to the database being down or hitting a deadlock. There is no reason that such errors should be returned to the client &amp;#8211; we can just rollback and try again. When an administrator brings the database back up, all the message waiting in the queue will then be processed successfully and our users receive confirmation. The system as a whole is quite a bit more robust to any error conditions. Thinking through the order in which commands and events are processed can lead to notification patterns which make returning errors unnecessary.&lt;/li&gt;&lt;li&gt;Command Handlers：The handlers of the command, one command only has one command handler; we&amp;#8217;re not returning errors to the client (who is already sending us valid commands), maybe all we need to do on the client when sending a command is to tell the user &amp;#8220;thank you, you will receive confirmation via email shortly&amp;#8221;. We don&amp;#8217;t even need the UI widget showing pending commands. Command handlers are responsible for:Performing any required validation on the command.Invoking the domain &amp;#8212; coordinating objects in the domain, and invoking the appropriate behaviour on them.Command handlers are application services, and each execution represents a separate unit of work (e.g. a database transaction). There is only one command handler per command, because commands can only be handled once &amp;#8212; they are not broadcast out to all interested listeners like event handlers.&lt;/li&gt;&lt;li&gt;Command Service：Dispatch the command to a corresponding command handler;&lt;/li&gt;&lt;li&gt;Domain: The DDD domain model, seperated by the aggregates, represents the domain structure and business logic; There is nothing that states that all commands must be processed by the same domain model. Arguably, you could have some commands be processed by transaction script, others using table module (AKA active record), as well as those using the domain model. Event-sourcing is another possible implementation. Another thing to understand about the domain model is that it now isn&amp;#8217;t used to serve queries. So the question is, why do you need to have so many relationships between entities in your domain model? Do we really need a collection of orders on the customer entity? In what command would we need to navigate that collection? In fact, what kind of command would need any one-to-many relationship? And if that&amp;#8217;s the case for one-to-many, many-to-many would definitely be out as well. I mean, most commands only contain one or two IDs in them anyway. Any aggregate operations that may have been calculated by looping over child entities could be pre-calculated and stored as properties on the parent entity. Following this process across all the entities in our domain would result in isolated entities needing nothing more than a couple of properties for the IDs of their related entities &amp;#8211; &amp;#8220;children&amp;#8221; holding the parent ID, like in databases. In this form, commands could be entirely processed by a single entity &amp;#8211; viola, an aggregate root that is a consistency boundary.&lt;/li&gt;&lt;li&gt;Aggregate: A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the Aggregate, designated as the root. A set of consistency rules applies within the Aggregate's boundaries. Problem: It is difficult to guarantee the consistency of changes to objects in a model with complex associations. Invariants need to be maintained that apply to closely related groups of objects, not just discrete objects. Yet cautious locking schemes cause multiple users to interfere pointlessly with each other and make a system unusable. [DDD, p. 126] Solution: Cluster the Entities and Value Objects into Aggregates and define boundaries around each. Choose one Entity to be the root of each Aggregate, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to root only. Transient references to the internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangemens makes it practical to enforce all invariants for objects in the Aggregate and for the Aggregate as a whole in any state change. The whole point of an aggregate and its aggregate root is to define an aggregate boundary. This boundary states that inside things should be consistent hence invariants should be satisfied. But it also means that outside, you cannot enforce invariants. If you need to enforce invariants outside an aggregate, it means, it's not a proper aggregate.&lt;/li&gt;&lt;li&gt;Domain Event：Represents what happened of the aggregates;&amp;nbsp;&lt;/li&gt;&lt;li&gt;Event Sourcing：Domain events can be used to rebuild the aggregate by replaying them of all;&lt;/li&gt;&lt;li&gt;Event Bus：A bus to publish domain event, there are synchronous event bus, asynchronous event bus, and composite event bus;&lt;/li&gt;&lt;li&gt;Repository：Act as an in-memory collection which contains all the aggregates;&lt;/li&gt;&lt;li&gt;Event Store: Stores all the persisted domain events;&lt;/li&gt;&lt;li&gt;Is suited to complex domains, commonly applied along with DDD;&lt;/li&gt;&lt;li&gt;Seperate the write and read model;&lt;/li&gt;&lt;li&gt;Use message to synchronize the write and read model, domain event is a type of message;&lt;/li&gt;&lt;li&gt;Task-based UI design;&lt;/li&gt;&lt;li&gt;One command effect one aggregate;&lt;/li&gt;&lt;li&gt;Aggregate defines the transactional consistency boundary; Inside the aggregate, consistency is guaranteed. Outside... it's not. So generally you should not have operations that spans several aggregates and have to be consistent. If you need a transaction that spans two aggregates, you should first review your aggregate boundaries.&lt;/li&gt;&lt;li&gt;Should know the distinction between: message, command, event;&lt;/li&gt;&lt;li&gt;Events are not about "field x changed", but about some change happening in real world with it's context and meaning, expressed in the language that makes sense to involved parties.&lt;/li&gt;&lt;li&gt;Event Sourcing should be used;&lt;/li&gt;&lt;li&gt;Use the eventual consistency to increase your saclability and availability, not transactional consistency;&lt;/li&gt;&lt;li&gt;We always use unit of work to tracking and store all the happened domain events;&lt;/li&gt;&lt;li&gt;There is no assurance of order between event handlers;&lt;/li&gt;&lt;li&gt;The inter-aggregate communication is a business process, and the best way to implement the business process (specially the long-running process transactions) is saga;&lt;/li&gt;&lt;li&gt;Aggregates receive commands and publish events, and sagas receive events and dispatch commands;&lt;/li&gt;&lt;li&gt;If there is a situation where more than a single AR was involved, that indicates that there was some sort of business process (as compared to business logic) will occur.&amp;nbsp;&lt;/li&gt;&lt;li&gt;How to persist the saga status? Also use the event sourcing, called state-change-sourced saga with a full history of state changes;&lt;/li&gt;&lt;li&gt;Rules to design aggregates: 1) model true invariants; 2)design small aggregates; 3) reference other aggregates by id; 4) Use eventual consistency between aggregates(after asking whose job it is);&lt;/li&gt;&lt;li&gt;In CQRS, the command handler is doing the same thing as the application service in Eric's DDD;&lt;/li&gt;&lt;li&gt;Command does not have return value, and we must ensure the command is valid before it is sent to server; When the command is processing asynchronously, we might show user information like "Your request is being processing, please wait for a few seconds.". As soon as the command is succeed (or failed), user is automatically taken to the next screen. This is trivial to do with AJAX in web UI. Desktop UIs are even simpler.&lt;/li&gt;&lt;li&gt;In some cases, use SendAndBlock pattern to communicate between web client and server; One thing to notice in the SendAndBlock is that the web page renders synchronously from the user's perspective, the interaction is synchronous and blocking, even though behind the scenes NServiceBus is doing asynchronous messaging.&lt;/li&gt;&lt;li&gt;There are two main integration points in Ncqrs-NServiceBus tandem. First one is transporting commands and the second one is publishing events.&lt;/li&gt;&lt;li&gt;There is not need the domain service(builder block in Eric's DDD) again, replaced by event and saga;&lt;/li&gt;&lt;li&gt;You should never delete an aggregate. You should mark it is out of date or unavailable. Deciding what to do with the remaining references is a business decision.&amp;nbsp;&lt;/li&gt;&lt;li&gt;There are two kinds of logic: 1) Processing domain logic; 2) Processing selection logic; Processing domain logic is the business logic that manipulates the application. Processing selection logic is the logic that chooses which chunk of processing domain logic should run depending on the incoming event. You can combine these together, essentially this is the Transaction Scriptapproach, but you can also separate them by putting the processing selection logic in the event processing system, and it calls a method in the domain model that contains the processing domain logic.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2332520.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2012/01/31/2332520.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/12/03/2274947.html</id><title type="text">分享一下我买过的书，有些还没看完</title><summary type="text">1. 书是学习知识最快的最系统的方法；2. 看名人Blog是学习正统知识第二个非常有效的方法；3. 我热衷于微软.NET平台下的web应用开发，对软件设计，软件工程也有一定兴趣；4. 近一年来以及将来重点关注DDD的理论研究和逐步实践；5. 知识就是金钱；6. 学习知识是一个循序渐进的过程，看的书也是有层次的；7. 只有有恒心和毅力，坚定的意志才能深入了解某门技术或设计或架构，才又机会知道某个领域中哪些问题值得去研究；8. 当你研究到一定程度，会发现国内与国外的差别，你才会感叹学好英语非常重要；9. 不要以为工作多年，写过很多软件，就是水平高，就具有设计能力；提高设计能力我觉得首先看你学习的方</summary><published>2011-12-03T12:44:00Z</published><updated>2011-12-03T12:44:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/12/03/2274947.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/12/03/2274947.html"/><content type="html">&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/netfocus/1.jpg" width="854" height="568" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/netfocus/2.jpg" width="1002" height="519" alt="" /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;1. 书是学习知识最快的最系统的方法；&lt;/p&gt;&lt;p&gt;2. 看名人Blog是学习正统知识第二个非常有效的方法；&lt;/p&gt;&lt;p&gt;3. 我热衷于微软.NET平台下的web应用开发，对软件设计，软件工程也有一定兴趣；&lt;/p&gt;&lt;p&gt;4. 近一年来以及将来重点关注DDD的理论研究和逐步实践；&lt;/p&gt;&lt;p&gt;5. 知识就是金钱；&lt;/p&gt;&lt;p&gt;6. 学习知识是一个循序渐进的过程，看的书也是有层次的；&lt;/p&gt;&lt;p&gt;7. 只有有恒心和毅力，坚定的意志才能深入了解某门技术或设计或架构，才又机会知道某个领域中哪些问题值得去研究；&lt;/p&gt;&lt;p&gt;8. 当你研究到一定程度，会发现国内与国外的差别，你才会感叹学好英语非常重要；&lt;/p&gt;&lt;p&gt;9. 不要以为工作多年，写过很多软件，就是水平高，就具有设计能力；提高设计能力我觉得首先看你学习的方向，第二看方法，第三看毅力；&lt;/p&gt;&lt;p&gt;10.平时把业余时间花在接私人项目，不如看本书，从长远看来，值得；&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;自己的不足，对一些较新的东西，如NoSQL,monodb,分布式缓存,Node.js,函数式编程,以及mono之类的还不太了解。另外，觉得还很有必要去学学哲学，尤其是逻辑哲学，计算机哲学。对软件设计，对OO的认识肯定有一些帮助，很多问题从哲学的角度去思考，会容易理解的多。&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2274947.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/12/03/2274947.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/12/03/2274680.html</id><title type="text">DDD Aggregate Definition</title><summary type="text">A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the Aggregate, designated as the root. A set of consistency rules applies within the Aggregate&amp;#39;s boundaries. Problem: It is difficult to guarantee the c</summary><published>2011-12-03T06:21:00Z</published><updated>2011-12-03T06:21:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/12/03/2274680.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/12/03/2274680.html"/><content type="html">&lt;div&gt;&lt;p&gt;&lt;strong&gt;&lt;div&gt;&lt;span style="font-family: Verdana, sans-serif; font-size: 12px; font-weight: normal; line-height: 20px; background-color: #ffffff; "&gt;A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the Aggregate, designated as the root. A set of consistency rules applies within the Aggregate's boundaries. Problem: It is difficult to guarantee the consistency of changes to objects in a model with complex associations. Invariants need to be maintained that apply to closely related groups of objects, not just discrete objects. Yet cautious locking schemes cause multiple users to interfere pointlessly with each other and make a system unusable. [DDD, p. 126] Solution: Cluster the&amp;nbsp;&lt;/span&gt;&lt;a href="http://domaindrivendesign.org/freelinking/Entities" style="color: #125b97; text-decoration: none; font-family: Verdana, sans-serif; font-size: 12px; font-weight: normal; line-height: 20px; background-color: #ffffff; "&gt;Entities&lt;/a&gt;&lt;span style="font-family: Verdana, sans-serif; font-size: 12px; font-weight: normal; line-height: 20px; background-color: #ffffff; "&gt;&amp;nbsp;and&amp;nbsp;&lt;/span&gt;&lt;a href="http://domaindrivendesign.org/freelinking/Value%2520Objects" style="color: #125b97; text-decoration: none; font-family: Verdana, sans-serif; font-size: 12px; font-weight: normal; line-height: 20px; background-color: #ffffff; "&gt;Value Objects&lt;/a&gt;&lt;span style="font-family: Verdana, sans-serif; font-size: 12px; font-weight: normal; line-height: 20px; background-color: #ffffff; "&gt;&amp;nbsp;into Aggregates and define boundaries around each. Choose one Entity to be the root of each Aggregate, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to root only. Transient references to the internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangemens makes it practical to enforce all invariants for objects in the Aggregate and for the Aggregate as a whole in any state change.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2274680.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/12/03/2274680.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/11/13/2247471.html</id><title type="text">领域驱动设计（DDD）学习成果精简总结，纯属个人经验，仅供参考（不断更新...）</title><summary type="text">以下这些点算是我对DDD学习的总结吧，我会在自己的学习过程中不断修正这些点或补充新的东西进来。学习要有积累，并且应该是简明扼要的积累。【补充，人总是在不断进步，所以很多观点也会随着时间的推移而改变。所以如果大家发现我以前的观点和这里有不同时，请理解一下，那只是表明我以前的理解。我最新的观点以这里为准。】 创建领域对象采用构造函数或者工厂，如果用工厂时需要依赖于领域服务或仓储，则通过构造函数注入到工厂； 一个聚合是由一些列相联的Entity和Value Object组成，一个聚合有一个聚合根，聚合根是Entity，整个聚合被看成是一个数据修改的单元，也就是说整个聚合内的所有对象要...</summary><published>2011-11-13T10:52:00Z</published><updated>2011-11-13T10:52:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/11/13/2247471.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/11/13/2247471.html"/><content type="html">&lt;span  style="background-color: #f3f3f3; "&gt;&#xD;
&lt;div style="font-family: 宋体, Arial; font-size: 12px; line-height: 20px; "&gt;以下这些点算是我对DDD学习的总结吧，我会在自己的学习过程中不断修正这些点或补充新的东西进来。学习要有积累，并且应该是简明扼要的积累。【补充，人总是在不断进步，所以很多观点也会随着时间的推移而改变。所以如果大家发现我以前的观点和这里有不同时，请理解一下，那只是表明我以前的理解。我最新的观点以这里为准。】&lt;/div&gt;&lt;p style="font-family: 宋体, Arial; font-size: 12px; line-height: 20px; "&gt;&lt;/p&gt;&lt;ol style="word-wrap: break-word; word-break: break-all; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; "&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;创建领域对象采用构造函数或者工厂，如果用工厂时需要依赖于领域服务或仓储，则通过构造函数注入到工厂；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;一个聚合是由一些列相联的Entity和Value Object组成，一个聚合有一个聚合根，聚合根是Entity，整个聚合被看成是一个&lt;strong&gt;数据修改的单元&lt;/strong&gt;，也就是说整个聚合内的所有对象要么同时被保存，要么都不能保存，即保存到数据持久层时必须以&lt;strong&gt;覆盖&lt;/strong&gt;的方式来保存，而不是追加方式或合并的方式来保存，否则无法确保聚合内的对象的&lt;strong&gt;数据一致性&lt;/strong&gt;。另外，整个聚合的不变性约束由聚合根负责维护。作为推导的一个结论：我们不能只保存一个聚合内的一部分对象；聚合内的所有实体和值对象应该总是一起被取出来一起被保存，因为一个聚合是一个数据持久化的单元，不需要考虑将整个聚合根取出来有性能问题，因为任何一个聚合根都有明确的边界。目前的内存缓存框架都已发展的比较成熟，性能已经不是问题；如MongoDb，MemCache，NoSQL，等等；&lt;/li&gt;&#xD;
     &lt;li style="word-wrap: break-word; word-break: break-all; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; "&gt;&lt;font  face="宋体, Arial"&gt;&lt;span  style="font-size: 12px; line-height: 20px;"&gt;聚合内的对象之所以聚合在一起的关键原因不是因为它们具有一些关联关系或依赖关系，&lt;strong&gt;而是因为聚合内的对象之间具有某些&lt;/strong&gt;&lt;/span&gt;&lt;/font&gt;&lt;strong style="font-family: 宋体, Arial; font-size: 12px; line-height: 20px; "&gt;不变性&lt;/strong&gt;&lt;font  face="宋体, Arial"&gt;&lt;span  style="font-size: 12px; line-height: 20px;"&gt;&lt;strong&gt;规则&lt;/strong&gt;，在任何时候，聚合内的所有这些对象必须满足这些不变性规则。&lt;strong&gt;所以，如果一些对象之间看似有一些关联关系或依赖关系，但是他们之间不具有任何不变性约束，那么就不应该把这些对象放在一个聚合中，否则只会增加这些对象之间不必要的耦合性，增加对象维护的难度&lt;/strong&gt;；(&lt;/span&gt;&lt;/font&gt;&lt;span  style="font-family: Georgia; font-size: 13px; line-height: normal; background-color: #ffffff; "&gt;Remembering that aggregates are not about composition, but about managing&amp;nbsp;&lt;/span&gt;&lt;font  face="宋体, Arial"&gt;&lt;span  style="font-size: 12px; line-height: 20px; "&gt;&lt;span  style="font-family: Georgia; font-size: 13px; line-height: normal; background-color: #ffffff; "&gt;invariants, we don't compose entities on an aggregate root only as a matter of convenience&lt;/span&gt;)。那么为什么一些对象之间有不变性约束后就一定非要聚合在一起不可呢？首先需要先明确一下什么是聚合，聚合是一个&lt;strong&gt;整体&lt;/strong&gt;，是&lt;strong&gt;修改数据的一个最小单元&lt;/strong&gt;，一个聚合有一个头，即聚合根，聚合根维护了整个聚合的不变性，&lt;strong&gt;所以整个聚合在外面看来就是一个对象，而不是多个对象的组合&lt;/strong&gt;。另外一点非常重要，聚合在被持久化到数据库时，是以完全覆盖的且事务的方式保存。好了有了前面的共识之后，我们再想想为什么聚合能保证多个对象之间的不变性规则约束？其实很只要真正理解了前面的约束之后就很容易理解了。你想想不管一个聚合中有什么约束，所有的约束由该聚合自己维护，所以就可以确保数据在领域模型级别就是完全一致的，没有任何违反规则的错误数据，即内存中的数据都是正确的。再加上这些正确的数据被持久化时是以完全覆盖的且事务的方式保存，从而也确保了数据库里的数据不可能出现不一致。这里唯一让你可能担心的问题是，如果多个用户同时更新一个聚合时，会产生并发冲突，此时将会使系统变得不可用！其实我认为这不是个问题，因为现在的支持高并发写的分布式存储数据库已经非常成熟，比如淘宝的oceanbase（已经开源了）,还有那些NoSQL也支持，或者用分布式缓存或MongoDB也效率不错。就算没这么好的存储机制支持，用传统的数据库来存储，我相信也不会有大问题，现在的数据库已经不是10年前的数据库了，在处理高并发写的能力上已经不是同日而语了。其实并发冲突并没有你想的那么严重，一般通过select before update，以及version乐观锁定，就没问题了。支付宝一天几千万比在线交易，全部是强一致性，不然不叫在线交易系统。聚合根的存储属于单点存储，不能用最终一致性。最终一致性是弱一致性的一种特殊方式，但是最终一致性往往用于处理分布式系统中同一份数据在多个地方有备份，然后可能会出现多个地方数据不一致的问题，但是最终都会一致即同步完成。具体大家可以看看CAP定理。&lt;/span&gt;&lt;/font&gt;&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;所谓的不变性约束是指：假设有一个采购订单Order，一个Order下有多个订单项OrderItem，假设有一个约束是，该采购订单的总额不能超过100元。那么订单的总额不能超过100元就是一个不变性约束；那么Order和OrderItem聚合在一起就显得很有意义。在这种情况下，有Order来维护这个规则，当整个订单被保存时，比如采用覆盖的方式保存到数据库。再举个例子，比如一个论坛中有帖子和回复，大家都知道一个帖子有多个回复，回复离开帖子没有意义。所以大家很自然会认为帖子和回复应该在一个聚合内，帖子是聚合根。但是这样其实很有问题，仔细想想会发现帖子和回复之间并没有不变性约束规则，回复和帖子之间只有一个简单的1:N的关系而已。如果每次在添加一个回复时，都把帖子先取出来，然后在帖子的回复列表中把新的回复添加进去，然后再保存整个帖子，那么不难想象，这样做无疑是小题大做，并且每次为了更新一个回复或新增一个回复，就要把整个帖子取出来，这样做无疑非常浪费内存，并且在多用户并发回同一个帖子的情况下则会更糟糕。实际上仔细分析一下，帖子和回复都应该是聚合，并且分别都是聚合根，我们要确保的仅仅是回复的帖子不能被修改即可。添加一个回复实际上和帖子无关，帖子根本不关心已经有多少个回复了。这点和之前的订单的例子不同，订单需要准确维护其&lt;strong&gt;包含&lt;/strong&gt;的所有订单项以便能够计算出总价是否超出100元。其实这么多问题还是不足以详细说明什么样的对象该被聚合在一起，这里只是作为抛砖引玉，引发大家思考如何设计聚合。&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;一个聚合需要具备哪些更多的特征呢？1）需要具备前面说的基本特征；2）聚合内的子对象要么是值对象，要么是只读的实体，为什么需要只读，因为聚合的子实体是可以被临时传递到外部的，要是外面的对象调用子对象的某个方法修改了子对象的属性，那么就意味着绕过聚合根修改了聚合内的东西，这样就无法确保聚合内的不变性了；3）如果聚合根有集合类型的属性，那么该集合也必须是只读的，即不允许别人在外部添加或删除集合的元素，否则也同样无法确保聚合的不变性。总之，我们要避免任何可能从外部修改聚合的行为发生，所有修改聚合的行为必须通过聚合根来实现。所以，理论上我们推荐大家在聚合内尽量设计值对象，原因大家多想想吧！其实从逻辑哲学的角度去思考，值对象表示了不变性，值对象表示一个值，值可以用来描述事物，事物就是实体。要是实体是由其他实体来描述，而其它实体是可变的，那么如何确保被描述的实体是可控的？大家想想为什么DDD书中，为什么要在OrderItem中存放当时购买时的Price就知道了。要是直接引用Product对象，那么会导致OrderItem引用了一个可变的对象，就无法确保订单的不变性约束。而唯有持久一个不变的值对象，才能维持其不变性。&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;Evans关于聚合的两条推荐准则：1）聚合不要设计的过大，过大的聚合很难确保不变性，从而很难确保数据的强一致性；2）聚合与聚合之间不要通过引用的方式来关联，而应该通过ID关联，通过ID关联也同样能表示聚合之间的关系，并且具有更好的性能和可伸缩性，聚合根之间通过ID关联的好处是：不会因为Load一个聚合根而把其他关联的聚合根一起Load出来，这样也避免了Load一个聚合根会把整个数据库Load出来的风险；另外，对ORM的要求也很低，不需要ORM支持LazyLoad；聚合根与聚合根之间的关系不像聚合内的Entity之间这么强烈内聚，它们之间仅仅是某种比较弱的关联关系，每个聚合根都有其独立的生命周期；&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&lt;div&gt;聚合内的非跟的Entity以及Value Object之间不要相互引用，聚合内的所有Child可以对根Entity持有引用，如果一个Child Entity需要和另外一个Child Entity交互，则因该通过聚合根完成；&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&#xD;
     &lt;div&gt;我们应该尽量减少聚合之间关联，尽量做到单向关联，只保留确实需要处理的经常需要用到的遍历方向的关联；&amp;nbsp;&lt;/div&gt;&#xD;
     &lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&lt;div&gt;仓储应理解为一个在内存中维护一系列聚合根的集合；&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&lt;div&gt;一个聚合根配备一个仓储；&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;仓储提供的接口应该总是接受聚合根或返回聚合根，不能返回聚合内的其他Entity或Value Object；&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&lt;div&gt;不要把仓储理解为DAO，仓储属于领域模型的一部分，代表了领域模型向外提供接口的一部分，而DAO是表示数据库向上层提供的接口表示；&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&lt;div&gt;仓储的目的不是为了支持界面查询，不要给仓储中设计一些目的是为了为界面提供显示数据的接口，仓储提供的所有接口应该仅为领域模型使用；基本的仓储接口只需要三个：Add，Remove，GetById，其他的扩展接口可以根据业务需要扩展接口声明；&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;如果一个操作仅由一个聚合根就可以完成，那么直接调用该聚合根完成即可；&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&lt;div&gt;领域服务表示领域模型中的一些业务操作，这些操作通常由多个聚合根或仓储或其他领域服务相互协作完成，那么需要为这些操作建立领域服务，在领域服务中以&lt;strong&gt;过程化的方式&lt;/strong&gt;来一步步首先根据各个聚合的ID获取到操作的相关聚合根，然后调用聚合根完成整个业务操作；比如资金转帐，这是经典的领域服务的例子；再比如在调用某个聚合根做一个数据更新之前需要先判断一些业务规则，但是这些判断规则不能在该聚合根内做，因为这样做可能会导致聚合根依赖于外部的领域服务或仓储，此时，应该交给领域服务来完成规则校验和聚合根数据更新的整个过程。领域服务可以依赖仓储或聚合根；&lt;/div&gt;&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;&lt;div&gt;领域服务依赖仓储时，工厂依赖于领域服务或仓储时，都因该采用构造函数注入的方式，这样可以避免领域模型中不会出现DependencyResolver.Resolve&amp;lt;T&amp;gt;()这样的语句；&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;切忌不要因为领域服务的引入让聚合根变得贫血，聚合根应该有的职责还是必须要由聚合根来承担；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;聚合根内不要依赖领域服务或仓储，如果你发现一个聚合根的职责需要依赖于某个领域服务或仓储来帮忙完成一些其他的逻辑（像判断业务规则之类），那么通常你要考虑这个职责不应该由该聚合根来承担，而应该建立合适的领域服务来承担；聚合根的主要职责是管理其内聚的所有Child Entity或Value Object的业务完整性；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;领域驱动设计时，为对象分配职责时，可以参考信息专家模式：将职责分配给拥有执行该职责所需信息的人；如果一个聚合根看起来拥有执行某个职责所需的信息，但没包含全部所需信息，此时则不应该将该职责分配给该聚合根，因为强行分配给它，会导致该聚合根没有内聚性，因为势必会依赖于其它的领域对象或领域服务或仓储；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;要学习CQRS架构，要知道我们应该将应用程序的业务逻辑处理部分（即用户命令响应部分）和查询部分分离；我们应该用两个不同的技术来实现这两个部分的实现；用DDD领域模型来实现命令部分；用最快的查询引擎来实现查询部分；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;如果要采用CQRS架构，我们需要考虑一个成熟可靠的底层框架，否则很容易导致命令端产生的领域对象的状态无法同步（后者丢失）到查询端的存储中；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;领域对象上的属性可以具有get和set，因为我们平时所理解的对象不是真正的对象，而是某个事实的描述，比如图书管理系统中的一个Book对象，表示图书管中放着一本书，然后该书可能有一个入库时间。现实生活正的话，书本的入库时间绝对不可能变化，但是软件中的Book因为不是真正的现实生活中的书本，而只是表示图书馆中有一本书这个事实的描述，我们当然可以修改这个事实，因为我们可能因为之前在书本入库时所输入的入库时间是错的，需要修改该入库时间，此时就有提供set的必要了。所以，理论上任何一个Entity，除了ID之外，其他所有属性都可以更改，因为这些属性并不表示现实生活中的真正对象的特征，而仅仅只是对一个事实的描述；刚开始Book对象对书本入库这个事实的描述可能有问题，此时我们就需要修改该Book的属性；我想这个例子已经充分说明为什么可以提供get和set了；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;不要总是零散的不加任何分组的设计Entity的属性，因为有些属性在逻辑上或业务上就是内聚的，代表一个完整的概念，比如Country,Province,City,Town,Street，等这些属性表示一个地址的信息，此时我们应该设计一个Address对象来表示该地址信息，此时该Address就是一个值对象。所以我们在设计Entity的属性时，要好好想想，哪些子属性其实在业务上是一个完整的概念，此时我们就需要考虑将这些相关的属性设计为一个值对象；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;切忌值对象必须是只读的，值对象之所以叫值对象最主要的是因为它表示一个值，而不是一个对象；值是不会变化的，是一个明确含义的不变的事物，比如3表示一个值，表述数量是3，3永远不能变化；所以说，世界之所以存在，是因为有这些永恒不变的值对象的存在；我们只要把值对象理解为3，&amp;#8220;abcd&amp;#8221;这样的永恒不变的值就行了；&lt;/li&gt;&#xD;
     &lt;li style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-right: auto; margin-bottom: 0px; margin-left: auto; line-height: 20px; "&gt;不要让领域模型去模拟现实，模拟用户（软件使用者）与领域模型交互的过程；领域模型要实现的应该是用户的需求，领域模型中不应该包含用户的成分，想想只有空杯子才能装水的道理，即无为以之用的道理就明白了；所以，我们在设计领域模型时首先要明白领域模型要完成的事情是什么；这方面，多看看用例图，就知道软件该做的事情了，推荐大家看的书是：Craig Larman写的《UML和模式应用》一书，非常经典；&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p style="font-family: 宋体, Arial; word-wrap: break-word; word-break: break-all; font-size: 12px; table-layout: fixed; margin-top: 0px; margin-bottom: 0px; line-height: 20px; "&gt;&lt;/p&gt;&#xD;
&lt;p style="font-family: 宋体, Arial; font-size: 12px; line-height: 20px; "&gt;更新于：2011-12-03&lt;/p&gt;&#xD;
&lt;/span&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2247471.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/11/13/2247471.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/11/02/2233734.html</id><title type="text">关于软件的任务到底是什么的思考</title><summary type="text">阅读本文需要有DDD，DCI的知识背景。首先，我觉得软件是用来被用户使用的，也就是说软件是用来帮用户完成一些事情的。从下面的用例图可以很好的理解用户与软件的关系：上图是超市里的一个营业员处理一笔销售的一个用例。从这个用例我们可以清楚的看到营业员和系统之间的一个交互。从中我们可以清晰的得出系统该做什么：makeNewSaleenterItemmakePayment这三个操作可以理解为用户希望软件为她做的三件事请。最近我惊奇的发现，DDD和DCI的一个巨大差别，让我不得不拿出来和大家确认。那就是：1）DDD强调软件不应该实现整个用例的交互过程，而应该只建立一个排除软件使用者的领域模型，该领域模型的</summary><published>2011-11-02T15:14:00Z</published><updated>2011-11-02T15:14:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/11/02/2233734.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/11/02/2233734.html"/><content type="html">&lt;p&gt;阅读本文需要有DDD，DCI的知识背景。&#xD;
首先，我觉得软件是用来被用户使用的，也就是说软件是用来帮用户完成一些事情的。从下面的用例图可以很好的理解用户与软件的关系：&#xD;
&lt;img src="http://images.cnblogs.com/cnblogs_com/netfocus/SystemSequenceDiagram.png" border="0" alt="" width="800" height="649" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span  style="background-color: #ffffff; "&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;上图是超市里的一个营业员处理一笔销售的一个用例。从这个用例我们可以清楚的看到营业员和系统之间的一个交互。从中我们可以清晰的得出系统该做什么：&lt;/div&gt;&#xD;
&lt;div&gt;makeNewSale&lt;/div&gt;&#xD;
&lt;div&gt;enterItem&lt;/div&gt;&#xD;
&lt;div&gt;makePayment&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div&gt;这三个操作可以理解为用户希望软件为她做的三件事请。最近我惊奇的发现，DDD和DCI的一个巨大差别，让我不得不拿出来和大家确认。那就是：&lt;/div&gt;&#xD;
&lt;div&gt;1）DDD强调软件不应该实现整个用例的交互过程，而应该只建立一个排除软件使用者的领域模型，该领域模型的目的不是要实现软件软件使用者与模型之间的交互过程，而是要捕捉和实现软件使用者提出的需求；&lt;/div&gt;&#xD;
&lt;div&gt;2）DCI强调软件应该实现整个用例的交互过程，在DCI的架构中，可能会有一个Person对象，然后扮演Cashier的角色参与到MakeNewSale或EnterItem等场景中去。&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;大家看到区别了吗？DDD更多的是把软件或者说把领域模型看成是一个&amp;#8220;工具&amp;#8221;，我们人类作为软件使用者通过使用这个工具来做一些事请；而DCI则是在模拟软件使用者与软件之间的整个交互过程，也就是说在DCI的架构中，我们能在内存中看到一个Cashier在做事情，就像现实生活中一样；而在DDD中，我们只会在内存中看到一些&amp;#8220;物&amp;#8221;在相互作用帮助软件使用者处理一些事情；简单的说：DCI是在完全模拟现实，而DDD则只侧重于表达除人之外的一个客观的&amp;#8220;物模型&amp;#8221;；&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;个人认为DDD的思想要比DCI好，因为虽然通过DDD思想建立出来的领域模型看起来是静态的，但我认为这恰恰是软件本质上该做的并且是只需要做的事情，事实上，我们都认为电脑是工具，我们建立领域模型目的也是为了用它，把它看成为一个工具而已。如果软件还要模拟人际交互的过程，那无疑会使软件（领域模型）不具有客观性。&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;&#xD;
&lt;p&gt;其实很多时候想想：&lt;/p&gt;&#xD;
&lt;div&gt;如果基于贫血模型的开发，那么软件只是一个帮助人类记录事实的工具，我们设计的对象没有任何行为，只是数据，就像数据库中的数据一样。事实上，数据库里存放的不是数据，而是事实的结果。比如数据库中有一条应聘记录，表示某个人在某个时候应聘过某个职位这个事实。所以，在贫血模型的开发模式下，我们的软件仅仅只是帮助我们记录事实的结果；&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;&#xD;
&lt;p&gt;而在DDD等倡导的充血模型的开发模式下，对象不仅仅只是一个记录事实结果的工具，而是一个个活生生的能够拥有自己个体行为以及能够和其他对象交互的交互行为的对象。此时，对象不仅可以记录事实结果，而且可以表示事实发生的原因，即对象之间的相互交互协作，即这个事实结果是通过怎样的事实产生的，其实从更高的层面上理解，对象之间交互是一种正在发生的事实。因此，基于DDD思想的对象不仅可以表示事实的结果，还能表示事实本身，即对象交互。但这个交互没有包含软件使用者与软件之间的交互，而仅仅表示软件领域模型中各个具有一定客观性的对象之间的交互；&lt;/p&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;&#xD;
&lt;p&gt;而在DCI的思想架构下，则认为软件除了要记录DDD所涉及的事实外，还应该表示出软件使用者与软件之间的整个交互事实；&lt;/p&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;&#xD;
&lt;p&gt;那么大家觉得哪个才是软件需要实现的真谛呢？&lt;/p&gt;&#xD;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;&#xD;
&lt;div&gt;呵呵，就这么多吧，话不多，但都是我深刻思考后的东西。希望大家也谈谈各自的看法。&amp;nbsp;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2233734.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/11/02/2233734.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/10/27/2225931.html</id><title type="text">DDD领域模型设计之--论坛</title><summary type="text">阅读本文的前提是假设你已经熟悉领域驱动设计（DDD）和CQRS架构。领域模型图如下：说明：上面的领域模型在设计时借鉴了DDD和CQRS的思想；利用DDD的思想来设计实体、值对象、聚合、聚合根；图中有三个聚合根，分别是Forum、Thread、User；其中Thread聚合根聚合了Post和ViewCounter两个对象；Post是Thread的回复，显然Post离开Thread没有意义，但是Post在Thread聚合内有一个本地标识，即只要在当前Thread下唯一即可，不需要全局唯一。由于CQRS思想的引入，可以确保我们在设计领域模型时不必考虑由于对象关联而产生的统计信息该如何存放，从而让领域</summary><published>2011-10-26T17:02:00Z</published><updated>2011-10-26T17:02:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/10/27/2225931.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/10/27/2225931.html"/><content type="html">&lt;p&gt;阅读本文的前提是假设你已经熟悉领域驱动设计（DDD）和CQRS架构。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;领域模型图如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/netfocus/ForumDomainModel.png" border="0" alt="" width="901" height="570" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;strong&gt;说明：&lt;/strong&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;上面的领域模型在设计时借鉴了DDD和CQRS的思想；&lt;/li&gt;&lt;li&gt;利用DDD的思想来设计实体、值对象、聚合、聚合根；图中有三个聚合根，分别是Forum、Thread、User；其中Thread聚合根聚合了Post和ViewCounter两个对象；Post是Thread的回复，显然Post离开Thread没有意义，但是Post在Thread聚合内有一个本地标识，即只要在当前Thread下唯一即可，不需要全局唯一。&lt;/li&gt;&lt;li&gt;由于CQRS思想的引入，可以确保我们在设计领域模型时不必考虑由于对象关联而产生的统计信息该如何存放，从而让领域模型更精简明了；如帖子的总回复数、最新回复时间、最新回复人，等等，这些信息只是统计信息，只用于在界面上显示，即我们只有在查询时才需要这些信息，因此可以在CQRS的Q端实现。&lt;/li&gt;&lt;li&gt;由于CQRS思想的引入，也可以让仓储更精简，不需要提供用于查询领域对象并在界面上显示结果的接口，而只需要提供用于查询单个聚合根或Add以及Remove的操作；&lt;/li&gt;&lt;li&gt;上面的领域模型只关注一个标准论坛的基本功能；&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;之前学了很多的理论知识，现在是该通过一些建模例子锻炼一下的时候了。相信大家一定有很多疑问，所以希望大家能多多讨论。今晚有点晚了，不能把整个思考过程写下来，到时我再补上。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2225931.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/10/27/2225931.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html</id><title type="text">分享我对领域驱动设计（DDD）的学习成果</title><summary type="text">本文内容提要：1. 领域驱动设计之领域模型；2. 为什么建立一个领域模型是重要的；3. 领域通用语言（Ubiquitous Language）；4. 将领域模型转换为代码实现的最佳实践；5. 领域建模时思考问题的角度；6. 领域驱动设计的标准分层架构；7. 领域驱动设计过程中使用的模式；8. 设计领域模型的一般步骤；9. 在分层架构中其他层如何与领域层交互；10.为什么面向对象比面向过程更能适应业务变化；11.领域驱动设计的其他一些主题；12.一些相关的扩展阅读；领域驱动设计之领域模型 2004年Eric Evans 发表Domain-Driven Design –Tackling Comp.</summary><published>2011-10-09T17:01:00Z</published><updated>2011-10-09T17:01:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html"/><content type="html">&lt;p&gt;&lt;strong&gt;&lt;p&gt;&lt;font  face="宋体" size="3"&gt;&lt;span  style="font-weight: normal; line-height: 24px;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;font  face="宋体" size="3"&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="font-family:宋体;"&gt;本文内容提要：&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;font  face="宋体" size="3" style="font-weight: normal;"&gt;&lt;p&gt;&lt;div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;1. 领域驱动设计之领域模型；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;2. 为什么建立一个领域模型是重要的；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;3. 领域通用语言（Ubiquitous Language）；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;4. 将领域模型转换为代码实现的最佳实践；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;5. 领域建模时思考问题的角度；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;6. 领域驱动设计的标准分层架构；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;7. 领域驱动设计过程中使用的模式；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;8. 设计领域模型的一般步骤；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;9. 在分层架构中其他层如何与领域层交互；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;10.为什么面向对象比面向过程更能适应业务变化；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;11.领域驱动设计的其他一些主题；&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: 10pt; "&gt;12.一些相关的扩展阅读；&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/p&gt;&lt;/font&gt;&lt;/div&gt;&lt;span  style="font-family: 宋体; "&gt;领域驱动设计之领域模型&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;2004&lt;span style="font-family:宋体;"&gt;年&lt;/span&gt;Eric Evans &lt;span style="font-family:宋体;"&gt;发表&lt;/span&gt;&lt;span&gt;Domain-Driven Design &amp;#8211;Tackling Complexity in the Heart of Software &lt;/span&gt;&lt;span style="font-family:宋体;"&gt;（领域驱动设计），简称&lt;/span&gt;&lt;span&gt;Evans DDD&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;。领域驱动设计分为两个阶段：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:21.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;以一种领域专家、设计人员、开发人员都能理解的&amp;#8220;通用语言&amp;#8221;作为相互交流的工具，在不断交流的过程中不断发现一些主要的领域概念，然后将这些概念设计成一个领域模型；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:21.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;由领域模型驱动软件设计，用代码来表现该领域模型。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;由此可见，领域驱动设计的核心是建立领域模型。领域模型在软件架构中处于核心地位；软件开发过程中，必须以建立领域模型为中心。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;为什么建立一个领域模型是重要的&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;领域驱动设计告诉我们，在通过软件实现一个业务系统时，建立一个领域模型是非常重要和必要的，因为领域模型具有以下特点：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;领域模型是对具有某个边界的领域的一个抽象，反映了领域内用户业务需求的本质；领域模型是有边界的，只反应了我们在领域内所关注的部分；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;领域模型只反映业务，和任何技术实现无关；领域模型不仅能反映领域中的一些实体概念，如货物，书本，应聘记录，地址，等；还能反映领域中的一些过程概念，如资金转账，等；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;3.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;领域模型确保了我们的软件的业务逻辑都在一个模型中，都在一个地方；这样对提高软件的可维护性，业务可理解性以及可重用性方面都有很好的帮助；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;4.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;领域模型能够帮助开发人员相对平滑地将领域知识转化为软件构造；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;5.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;领域模型贯穿软件分析、设计，以及开发的整个过程；领域专家、设计人员、开发人员通过领域模型进行交流，彼此共享知识与信息；因为大家面向的都是同一个模型，&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;所以可以防止需求走样，可以让软件设计开发人员做出来的软件真正满足需求；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;6.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;要建立正确的领域模型并不简单，需要领域专家、设计、开发人员积极沟通共同努力，然后才能使大家对领域的认识不断深入，从而不断细化和完善领域模型；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;7.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;为了让领域模型看的见，我们需要用一些方法来表示它；图是表达领域模型最常用的方式，但不是唯一的表达方式，代码或文字描述也能表达领域模型；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:42.0pt;text-indent:-21.0pt;"&gt;&lt;span&gt;&lt;span&gt;8.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;领域模型是整个软件的核心，是软件中最有价值和最具竞争力的部分；设计足够精良且符合业务需求的领域模型能够更快速的响应需求变化；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;领域通用语言（&lt;/span&gt;&lt;span style="line-height:240%;"&gt;Ubiquitous Language&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;）&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;我们认识到由软件专家和领域专家通力合作开发出一个领域的模型是绝对需要的，但是，那种方法通常会由于一些基础交流的障碍而存在难点。开发人员满脑子都是类、方法、算法、模式、架构，等等，总是想将实际生活中的概念和程序工件进行对应。他们希望看到要建立哪些对象类，要如何对对象类之间的关系建模。他们会习惯按照封装、继承、多态等面向对象编程中的概念去思考，会随时随地这样交谈，这对他们来说这太正常不过了，开发人员就是开发人员。但是领域专家通常对这一无所知，他们对软件类库、框架、持久化甚至数据库没有什么概念。他们只了解他们特有的领域专业技能。比如，在空中交通监控样例中，领域专家知道飞机、路线、海拔、经度、纬度，知道飞机偏离了正常路线，知道飞机的发射。他们用他们自己的术语讨论这些事情，有时这对于外行来说很难直接理解。如果一个人说了什么事情，其他的人不能理解，或者更糟的是错误理解成其他事情，又有什么机会来保证项目成功呢？&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;在交流的过程中，需要做翻译才能让其他的人理解这些概念。开发人员可能会努力使用外行人的语言来解析一些设计模式，但这并一定都能成功奏效。领域专家也可能会创建一种新的行话以努力表达他们的这些想法。在这个痛苦的交流过程中，这种类型的翻译并不能对知识的构建过程产生帮助。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;领域驱动设计的一个核心的原则是使用一种基于模型的语言。因为模型是软件满足领域的共同点，它很适合作为这种通用语言的构造基础。使用模型作为语言的核心骨架，要求团队在进行所有的交流是都使用一致的语言，在代码中也是这样。在共享知识和推敲模型时，团队会使用演讲、文字和图形。这儿需要确保团队使用的语言在所有的交流形式中看上去都是一致的，这种语言被称为&amp;#8220;通用语言（&lt;/span&gt;Ubiquitous Language&lt;span style="font-family:宋体;"&gt;）&amp;#8221;。通用语言应该在建模过程中广泛尝试以推动软件专家和领域专家之间的沟通，从而发现要在模型中使用的主要的领域概念。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;将领域模型转换为代码实现的最佳实践&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;拥有一个看上去正确的模型不代表模型能被直接转换成代码，也或者它的实现可能会违背某些我们所不建议的软件设计原则。我们该如何实现从模型到代码的转换，并让代码具有可扩展性、可维护性，高性能等指标呢？另外，如实反映领域的模型可能会导致对象持久化的一系列问题，或者导致不可接受的性能问题。那么我们应该怎么做呢？&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;我们应该紧密关联领域建模和设计，紧密将领域模型和软件编码实现捆绑在一起，模型在构建时就考虑到软件和设计。开发人员会被加入到建模的过程中来。主要的想法是选择一个能够恰当在软件中表现的模型，这样设计过程会很顺畅并且基于模型。代码和其下的模型紧密关联会让代码更有意义并与模型更相关。有了开发人员的参与就会有反馈。它能保证模型被实现成软件。如果其中某处有错误，会在早期就被标识出来，问题也会容易修正。写代码的人会很好地了解模型，会感觉自己有责任保持它的完整性。他们会意识到对代码的一个变更其实就隐含着对模型的变更，另外，如果哪里的代码不能表现原始模型的话，他们会重构代码。如果分析人员从实现过程中分离出去，他会不再关心开发过程中引入的局限性。最终结果是模型不再实用。任何技术人员想对模型做出贡献必须花费一些时间来接触代码，无论他在项目中担负的是什么主要角色。任何一个负责修改代码的人都必须学会用代码表现模型。每位开发人员都必须参与到一定级别的领域讨论中并和领域专家联络。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;领域建模时思考问题的角度&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;&amp;#8220;用户需求&amp;#8221;不能等同于&amp;#8220;用户&amp;#8221;，捕捉&amp;#8220;用户心中的模型&amp;#8221;也不能等同于&amp;#8220;以用户为核心设计领域模型&amp;#8221;。&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;《老子》书中有个观点：有之以为利，无之以为用。在这里，有之利，即建立领域模型；无之用，即包容用户需求。举些例子，一个杯子要装满一杯水，我们在制作杯子时，制作的是空杯子，即要把水倒出来，之后才能装下水；再比如，一座房子要住人，我们在建造房子时，建造的房子是空的，唯有空的才能容纳人的居住。因此，建立领域模型时也要将用户置于模型之外，这样才能包容用户的需求。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;所以，我的理解是：&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;text-autospace:none"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;我们设计领域模型时不能以用户为中心作为出发点去思考问题，不能老是想着用户会对系统做什么；而应该从一个客观的角度，根据用户需求挖掘出领域内的相关事物，思考这些事物的本质关联及其变化规律作为出发点去思考问题。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;text-autospace:none"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=" font-family:宋体;color:#222222; background:white"&gt;领域模型是排除了人之外的客观世界模型，但是领域模型包含人所扮演的参与者角色，但是一般情况下不要让参与者角色在领域模型中占据主要位置，如果以人所扮演的参与者角色在领域模型中占据主要位置，那么各个系统的领域模型将变得没有差别，因为软件系统就是一个人机交互的系统，都是以人为主的活动记录或跟踪；比如：论坛中如果以人为主导，那么领域模型就是：人发帖，人回帖，人结贴，等等；&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;; color:#222222;background:white"&gt;DDD&lt;/span&gt;&lt;span style=" font-family:宋体;color:#222222; background:white"&gt;的例子中，如果是以人为中心的话，就变成了：托运人托运货物，收货人收货物，付款人付款，等等；因此，当我们谈及领域模型时，已经默认把人的因素排除开了，因为领域只有对人来说才有意义，人是在领域范围之外的，如果人也划入领域，领域模型将很难保持客观性。领域模型是与谁用和怎样用是无关的客观模型。归纳起来说就是，领域建模是建立虚拟模型让我们现实的人使用，而不是建立虚拟空间，去模仿现实。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;以&lt;/span&gt;Eric Evans&lt;span style="font-family:宋体;"&gt;（&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;之父）在他的书中的一个货物运输系统为例子简单说明一下。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;在经过一些用户需求讨论之后，在用户需求相对明朗之后，&lt;/span&gt;Eric&lt;span style="font-family:宋体;"&gt;这样描述领域模型：&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:21.0pt;text-align:left; text-indent:-21.0pt;text-autospace:none"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;一个&lt;/span&gt;Cargo&lt;span style="font-family:宋体;"&gt;（货物）涉及多个&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;（客户，如托运人、收货人、付款人），每个&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;承担不同的角色；&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:21.0pt;text-align:left; text-indent:-21.0pt;text-autospace:none"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Cargo&lt;span style="font-family:宋体;"&gt;的运送目标已指定，即&lt;/span&gt;Cargo&lt;span style="font-family:宋体;"&gt;有一个运送目标；&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:21.0pt;text-align:left; text-indent:-21.0pt;text-autospace:none"&gt;&lt;span&gt;&lt;span&gt;3.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;由一系列满足&lt;/span&gt;Specification&lt;span style="font-family:宋体;"&gt;（规格）的&lt;/span&gt;Carrier Movement&lt;span style="font-family:宋体;"&gt;（运输动作）来完成运输目标；&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;从上面的描述我们可以看出，他完全没有从用户的角度去描述领域模型，而是以领域内的相关事物为出发点，考虑这些事物的本质关联及其变化规律的。上述这段描述完全以货物为中心，把客户看成是货物在某个场景中可能会涉及到的关联角色，如货物会涉及到托运人、收货人、付款人；货物有一个确定的目标，货物会经过一系列列的运输动作到达目的地；其实，我觉得以用户为中心来思考领域模型的思维只是停留在需求的表面，而没有挖掘出真正的需求的本质；我们在做领域建模时需要努力挖掘用户需求的本质，这样才能真正实现用户需求；&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family:宋体;"&gt;关于用户、参与者这两个概念的区分，可以看一下下面的例子：&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family: 宋体;color:#222222;background:white"&gt;试想两个人共同玩足球游戏，操作者（用户）是驱动者，它驱使足球比赛领域中，各个&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;; color:#222222;background:white"&gt;&amp;#8220;&lt;/span&gt;&lt;span style=" font-family:宋体;color:#222222; background:white"&gt;人&lt;/span&gt;&lt;span style=" font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222;background:white"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;（参与者）的活动。这里立下一个假设，假设操作者&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;; color:#222222;background:white"&gt;A&lt;/span&gt;&lt;span style=" font-family:宋体;color:#222222; background:white"&gt;操作某一队员&lt;/span&gt;&lt;span style=" font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222;background:white"&gt;a&lt;/span&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;，而队员&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222; background:white"&gt;a&lt;/span&gt;&lt;span style="font-family: 宋体;color:#222222;background:white"&gt;拥有着某人&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;; color:#222222;background:white"&gt;B&lt;/span&gt;&lt;span style=" font-family:宋体;color:#222222; background:white"&gt;的信息，那么有以下说法，&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222;background:white"&gt;a&lt;/span&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;是&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222; background:white"&gt;B&lt;/span&gt;&lt;span style="font-family: 宋体;color:#222222;background:white"&gt;的镜像，&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;; color:#222222;background:white"&gt;a&lt;/span&gt;&lt;span style=" font-family:宋体;color:#222222; background:white"&gt;是领域参与者，&lt;/span&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222;background:white"&gt;A&lt;/span&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;是驱动者。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;领域驱动设计的标准分层架构&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://www.entityspider.com/uploadfiles/ddd_architecture.png" border="0" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;用户界面&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;; color:#222222;background:white"&gt;/&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;展现层&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family: 宋体;color:#222222;background:white"&gt;负责向用户展现信息以及解释用户命令。更细的方面来讲就是：&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;text-autospace:none"&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222"&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;请求应用层以获取用户所需要展现的数据；&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;text-autospace:none"&gt;&lt;span style="font-family:&amp;quot;Verdana&amp;quot;,&amp;quot;sans-serif&amp;quot;;color:#222222"&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;发送命令给应用层要求其执行某个用户命令；&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;strong&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;应用层&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family: 宋体;color:#222222;background:white"&gt;很薄的一层，定义软件要完成的所有任务。对外为展现层提供各种应用功能（包括查询或命令），对内调用领域层（领域对象或领域服务）完成各种业务逻辑，应用层不包含业务逻辑。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;strong&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;领域层&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family: 宋体;color:#222222;background:white"&gt;负责表达业务概念，业务状态信息以及业务规则，领域模型处于这一层，是业务软件的核心。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;strong&gt;&lt;span style="font-family:宋体;color:#222222;background:white"&gt;基础设施层&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;text-autospace:none"&gt;&lt;span style="font-family: 宋体;color:#222222;background:white"&gt;本层为其他层提供通用的技术能力；提供了层间的通信；为领域层实现持久化机制；总之，基础设施层可以通过架构和框架来支持其他层的技术需求；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;领域驱动设计过程中使用的模式&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;所有模式的总揽图：&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.entityspider.com/uploadfiles/ddd_total_patterns.png" border="0" alt="" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;关联的设计&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;关联本身不是一个模式，但它在领域建模的过程中非常重要，所以需要在探讨各种模式之前，先讨论一下对象之间的关联该如何设计。我觉得对象的关联的设计可以遵循如下的一些原则：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;关联尽量少，对象之间的复杂的关联容易形成对象的关系网，这样对于我们理解和维护单个对象很不利，同时也很难划分对象与对象之间的边界；另外，同时减少关联有助于简化对象之间的遍历；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;1&lt;span style="font-family: 宋体;"&gt;对多的关联也许在业务上是很自然的，通常我们会用一个集合来表示&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;对多的关系。但我们往往也需要考虑到性能问题，尤其是当集合内元素非常多的时候，此时往往需要通过单独查询来获取关联的集合信息；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;3.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;关联尽量保持单向的关联；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;4.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;在建立关联时，我们需要深入去挖掘是否存在关联的限制条件，如果存在，那么最好把这个限制条件加到这个关联上；往往这样的限制条件能将关联化繁为简，即可以将多对多简化为&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;对多，或将&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;对多简化为&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;对&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;实体（&lt;/span&gt;Entity&lt;span style="font-family:宋体;"&gt;）：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;实体就是领域中需要唯一标识的领域概念。因为我们有时需要区分是哪个实体。有两个实体，如果唯一标识不一样，那么即便实体的其他所有属性都一样，我们也认为他们两个不同的实体；因为实体有生命周期，实体从被创建后可能会被持久化到数据库，然后某个时候又会被取出来。所以，如果我们不为实体定义一种可以唯一区分的标识，那我们就无法区分到底是这个实体还是哪个实体。另外，不应该给实体定义太多的属性或行为，而应该寻找关联，发现其他一些实体或值对象，将属性或行为转移到其他关联的实体或值对象上。比如&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;实体，他有一些地址信息，由于地址信息是一个完整的有业务含义的概念，所以，我们可以定义一个&lt;/span&gt;Address&lt;span style="font-family:宋体;"&gt;对象，然后把&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;的地址相关的信息转移到&lt;/span&gt;Address&lt;span style="font-family:宋体;"&gt;对象上。如果没有&lt;/span&gt;Address&lt;span style="font-family:宋体;"&gt;对象，而把这些地址信息直接放在&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;对象上，并且如果对于一些其他的类似&lt;/span&gt;Address&lt;span style="font-family:宋体;"&gt;的信息也都直接放在&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;上，会导致&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;对象很混乱，结构不清晰，最终导致它难以维护和理解；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;值对象（&lt;/span&gt;Value Object&lt;span style="font-family:宋体;"&gt;）：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;在领域中，并不是没一个事物都必须有一个唯一标识，也就是说我们不关心对象是哪个，而只关心对象是什么。就以上面的地址对象&lt;/span&gt;Address&lt;span style="font-family:宋体;"&gt;为例，如果有两个&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;的地址信息是一样的，我们就会认为这两个&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;的地址是同一个。也就是说只要地址信息一样，我们就认为是同一个地址。用程序的方式来表达就是，如果两个对象的所有的属性的值都相同我们会认为它们是同一个对象的话，那么我们就可以把这种对象设计为值对象。因此，值对象没有唯一标识，这是它和实体的最大不同。另外值对象在判断是否是同一个对象时是通过它们的所有属性是否相同，如果相同则认为是同一个值对象；而我们在区分是否是同一个实体时，只看实体的唯一标识是否相同，而不管实体的属性是否相同；值对象另外一个明显的特征是不可变，即所有属性都是只读的。因为属性是只读的，所以可以被安全的共享；当共享值对象时，一般有复制和共享两种做法，具体采用哪种做法还要根据实际情况而定；另外，我们应该给值对象设计的尽量简单，不要让它引用很多其他的对象，因为他只是一个值，就像&lt;/span&gt;int a = 3;&lt;span style="font-family:宋体;"&gt;那么&lt;/span&gt;&amp;#8221;3&amp;#8221;&lt;span style="font-family:宋体;"&gt;就是一个我们传统意义上所说的值，而值对象其实也可以和这里的&lt;/span&gt;&amp;#8221;3&amp;#8221;&lt;span style="font-family:宋体;"&gt;一样理解，也是一个值，只不过是用对象来表示。所以，当我们在&lt;/span&gt;C#&lt;span style="font-family:宋体;"&gt;语言中比较两个值对象是否相等时，会重写&lt;/span&gt;GetHashCode&lt;span style="font-family:宋体;"&gt;和&lt;/span&gt;Equals&lt;span style="font-family:宋体;"&gt;这两个方法，目的就是为了比较对象的值；值对象虽然是只读的，但是可以被整个替换掉。就像你把&lt;/span&gt;a&lt;span style="font-family:宋体;"&gt;的值修改为&lt;/span&gt;&amp;#8221;4&amp;#8221;(a = 4;)&lt;span style="font-family:宋体;"&gt;一样，直接把&lt;/span&gt;&amp;#8221;3&amp;#8221;&lt;span style="font-family:宋体;"&gt;这个值替换为&lt;/span&gt;&amp;#8221;4&amp;#8221;&lt;span style="font-family:宋体;"&gt;了。值对象也是一样，当你要修改&lt;/span&gt;Customer&lt;span style="font-family:宋体;"&gt;的&lt;/span&gt;Address&lt;span style="font-family:宋体;"&gt;对象引用时，不是通过&lt;/span&gt;Customer.Address.Street&lt;span style="font-family:宋体;"&gt;这样的方式来实现，因为值对象是只读的，它是一个完整的不可分割的整体。我们可以这样做：&lt;/span&gt;Customer.Address = new Address(&amp;#8230;);&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;领域服务（&lt;/span&gt;Domain Service&lt;span style="font-family:宋体;"&gt;）：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;领域中的一些概念不太适合建模为对象，即归类到实体对象或值对象，因为它们本质上就是一些操作，一些动作，而不是事物。这些操作或动作往往会涉及到多个领域对象，并且需要协调这些领域对象共同完成这个操作或动作。如果强行将这些操作职责分配给任何一个对象，则被分配的对象就是承担一些不该承担的职责，从而会导致对象的职责不明确很混乱。但是基于类的面向对象语言规定任何属性或行为都必须放在对象里面。所以我们需要寻找一种新的模式来表示这种跨多个对象的操作，&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;认为服务是一个很自然的范式用来对应这种跨多个对象的操作，所以就有了领域服务这个模式。和领域对象不同，领域服务是以动词开头来命名的，比如资金转帐服务可以命名为&lt;/span&gt;MoneyTransferService&lt;span style="font-family:宋体;"&gt;。当然，你也可以把服务理解为一个对象，但这和一般意义上的对象有些区别。因为一般的领域对象都是有状态和行为的，而领域服务没有状态只有行为。需要强调的是领域服务是无状态的，它存在的意义就是协调领域对象共完成某个操作，所有的状态还是都保存在相应的领域对象中。我觉得模型（实体）与服务（场景）是对领域的一种划分，模型关注领域的个体行为，场景关注领域的群体行为，模型关注领域的静态结构，场景关注领域的动态功能。这也符合了现实中出现的各种现象，有动有静，有独立有协作。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;领域服务还有一个很重要的功能就是可以避免领域逻辑泄露到应用层。因为如果没有领域服务，那么应用层会直接调用领域对象完成本该是属于领域服务该做的操作，这样一来，领域层可能会把一部分领域知识泄露到应用层。因为应用层需要了解每个领域对象的业务功能，具有哪些信息，以及它可能会与哪些其他领域对象交互，怎么交互等一系列领域知识。因此，引入领域服务可以有效的防治领域层的逻辑泄露到应用层。对于应用层来说，从可理解的角度来讲，通过调用领域服务提供的简单易懂但意义明确的接口肯定也要比直接操纵领域对象容易的多。这里似乎也看到了领域服务具有&lt;/span&gt;Fa&amp;#231;ade&lt;span style="font-family:宋体;"&gt;的功能，呵呵。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;说到领域服务，还需要提一下软件中一般有三种服务：应用层服务、领域服务、基础服务。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;比如应用层有一个资金转帐的服务，该服务主要做以下事情：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;1）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;获取输入（如一个&lt;/span&gt;XML&lt;span style="font-family:宋体;"&gt;请求）；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;2）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;发送消息给领域层服务，要求其实现转帐的业务逻辑；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;3）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;领域层服务处理成功，则调用基础层服务发送&lt;/span&gt;Email&lt;span style="font-family:宋体;"&gt;通知；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;领域层的服务做以下事情：&lt;/span&gt;&lt;/strong&gt;&lt;span&gt;&lt;br /&gt; 1&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;）获取源帐号和目标帐号，分别通知源帐号和目标帐号进行扣除金额和增加金额的操作；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;2&lt;span style="font-family:宋体;"&gt;）提供返回结果给应用层；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;基础层服务做以下事情：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;按照应用层的请求，发送&lt;/span&gt;Email&lt;span style="font-family:宋体;"&gt;通知；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;所以，从上面的例子中可以清晰的看出，每种服务的职责；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;聚合及聚合根（&lt;/span&gt;Aggregate&lt;span style="font-family:宋体;"&gt;，&lt;/span&gt;Aggregate Root&lt;span style="font-family:宋体;"&gt;）：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;聚合，它通过定义对象之间清晰的所属关系和边界来实现领域模型的内聚，并避免了错综复杂的难以维护的对象关系网的形成。聚合定义了一组具有内聚关系的相关对象的集合，我们把聚合看作是一个修改数据的单元。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;聚合有以下一些特点：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;每个聚合有一个根和一个边界，边界定义了一个聚合内部有哪些实体或值对象，根是聚合内的某个实体；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;聚合内部的对象之间可以相互引用，但是聚合外部如果要访问聚合内部的对象时，必须通过聚合根开始导航，绝对不能绕过聚合根直接访问聚合内的对象，也就是说聚合根是外部可以保持 &amp;nbsp;对它的引用的唯一元素；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;3.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;聚合内除根以外的其他实体的唯一标识都是本地标识，也就是只要在聚合内部保持唯一即可，因为它们总是从属于这个聚合的；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;4.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;聚合根负责与外部其他对象打交道并维护自己内部的业务规则；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;5.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;基于聚合的以上概念，我们可以推论出从数据库查询时的单元也是以聚合为一个单元，也就是说我们不能直接查询聚合内部的某个非根的对象；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;6.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;聚合内部的对象可以保持对其他聚合根的引用；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;7.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;删除一个聚合根时必须同时删除该聚合内的所有相关对象，因为他们都同属于一个聚合，是一个完整的概念；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;关于如何识别聚合以及聚合根的问题：&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;我觉得我们可以先从业务的角度深入思考，然后慢慢分析出有哪些对象是：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;1）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;有独立存在的意义，即它是不依赖于其他对象的存在它才有意义的；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;2）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;可以被独立访问的，还是必须通过某个其他对象导航得到的；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;如何识别聚合？&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;我觉得这个需要从业务的角度深入分析哪些对象它们的关系是内聚的，即我们会把他们看成是一个整体来考虑的；然后这些对象我们就可以把它们放在一个聚合内。所谓关系是内聚的，是指这些对象之间必须保持一个固定规则，固定规则是指在数据变化时必须保持不变的一致性规则。当我们在修改一个聚合时，我们必须在事务级别确保整个聚合内的所有对象满足这个固定规则。作为一条建议，聚合尽量不要太大，否则即便能够做到在事务级别保持聚合的业务规则完整性，也可能会带来一定的性能问题。有分析报告显示，通常在大部分领域模型中，有&lt;/span&gt;70%&lt;span style="font-family:宋体;"&gt;的聚合通常只有一个实体，即聚合根，该实体内部没有包含其他实体，只包含一些值对象；另外&lt;/span&gt;30%&lt;span style="font-family:宋体;"&gt;的聚合中，基本上也只包含两到三个实体。这意味着大部分的聚合都只是一个实体，该实体同时也是聚合根。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;如何识别聚合根？&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;如果一个聚合只有一个实体，那么这个实体就是聚合根；如果有多个实体，那么我们可以思考聚合内哪个对象有独立存在的意义并且可以和外部直接进行交互。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;工厂（&lt;/span&gt;Factory&lt;span style="font-family:宋体;"&gt;）：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;DDD&lt;span style="font-family:宋体;"&gt;中的工厂也是一种体现封装思想的模式。&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中引入工厂模式的原因是：有时创建一个领域对象是一件比较复杂的事情，不仅仅是简单的&lt;/span&gt;new&lt;span style="font-family:宋体;"&gt;操作。正如对象封装了内部实现一样（我们无需知道对象的内部实现就可以使用对象的行为），工厂则是用来封装创建一个复杂对象尤其是聚合时所需的知识，工厂的作用是将创建对象的细节隐藏起来。客户传递给工厂一些简单的参数，然后工厂可以在内部创建出一个复杂的领域对象然后返回给客户。领域模型中其他元素都不适合做这个事情，所以需要引入这个新的模式，工厂。工厂在创建一个复杂的领域对象时，通常会知道该满足什么业务规则（它知道先怎样实例化一个对象，然后在对这个对象做哪些初始化操作，这些知识就是创建对象的细节），如果传递进来的参数符合创建对象的业务规则，则可以顺利创建相应的对象；但是如果由于参数无效等原因不能创建出期望的对象时，应该抛出一个异常，以确保不会创建出一个错误的对象。当然我们也并不总是需要通过工厂来创建对象，事实上大部分情况下领域对象的创建都不会太复杂，所以我们只需要简单的使用构造函数创建对象就可以了。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;隐藏创建对象的好处是显而易见的，这样可以不会让领域层的业务逻辑泄露到应用层，同时也减轻了应用层的负担，它只需要简单的调用领域工厂创建出期望的对象即可。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;仓储（&lt;/span&gt;Repository&lt;span style="font-family:宋体;"&gt;）：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;1）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;仓储被设计出来的目的是基于这个原因：领域模型中的对象自从被创建出来后不会一直留在内存中活动的，当它不活动时会被持久化到数据库中，然后当需要的时候我们会重建该对象；重建对象就是根据数据库中已存储的对象的状态重新创建对象的过程；所以，可见重建对象是一个和数据库打交道的过程。从更广义的角度来理解，我们经常会像集合一样从某个类似集合的地方根据某个条件获取一个或一些对象，往集合中添加对象或移除对象。也就是说，我们需要提供一种机制，可以提供类似集合的接口来帮助我们管理对象。仓储就是基于这样的思想被设计出来的；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;2）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;仓储里面存放的对象一定是聚合，原因是之前提到的领域模型中是以聚合的概念去划分边界的；聚合是我们更新对象的一个边界，事实上我们把整个聚合看成是一个整体概念，要么一起被取出来，要么一起被删除。我们永远不会单独对某个聚合内的子对象进行单独查询或做更新操作。因此，我们只对聚合设计仓储。&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;3）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;仓储还有一个重要的特征就是分为仓储定义部分和仓储实现部分，在领域模型中我们定义仓储的接口，而在基础设施层实现具体的仓储。这样做的原因是：由于仓储背后的实现都是在和数据库打交道，但是我们又不希望客户（如应用层）把重点放在如何从数据库获取数据的问题上，因为这样做会导致客户（应用层）代码很混乱，很可能会因此而忽略了领域模型的存在。所以我们需要提供一个简单明了的接口，供客户使用，确保客户能以最简单的方式获取领域对象，从而可以让它专心的不会被什么数据访问代码打扰的情况下协调领域对象完成业务逻辑。这种通过接口来隔离封装变化的做法其实很常见。由于客户面对的是抽象的接口并不是具体的实现，所以我们可以随时替换仓储的真实实现，这很有助于我们做单元测试。&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;4）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;尽管仓储可以像集合一样在内存中管理对象，但是仓储一般不负责事务处理。一般事务处理会交给一个叫&amp;#8220;工作单元（&lt;/span&gt;Unit Of Work&lt;span style="font-family:宋体;"&gt;）&amp;#8221;的东西。关于工作单元的详细信息我在下面的讨论中会讲到。&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;5）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;另外，仓储在设计查询接口时，可能还会用到规格模式（&lt;/span&gt;Specification Pattern&lt;span style="font-family:宋体;"&gt;），我见过的最厉害的规格模式应该就是&lt;/span&gt;LINQ&lt;span style="font-family:宋体;"&gt;以及&lt;/span&gt;DLINQ&lt;span style="font-family:宋体;"&gt;查询了。一般我们会根据项目中查询的灵活度要求来选择适合的仓储查询接口设计。通常情况下只需要定义简单明了的具有固定查询参数的查询接口就可以了。只有是在查询条件是动态指定的情况下才可能需要用到&lt;/span&gt;Specification&lt;span style="font-family:宋体;"&gt;等模式。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;设计领域模型的一般步骤：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;根据需求建立一个初步的领域模型，识别出一些明显的领域概念以及它们的关联，关联可以暂时没有方向但需要有（&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;：&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;，&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;：&lt;/span&gt;N&lt;span style="font-family:宋体;"&gt;，&lt;/span&gt;M&lt;span style="font-family:宋体;"&gt;：&lt;/span&gt;N&lt;span style="font-family:宋体;"&gt;）这些关系；可以用文字精确的没有歧义的描述出每个领域概念的涵义以及包含的主要信息；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;分析主要的软件应用程序功能，识别出主要的应用层的类；这样有助于及早发现哪些是应用层的职责，哪些是领域层的职责；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;3.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;进一步分析领域模型，识别出哪些是实体，哪些是值对象，哪些是领域服务；&lt;/span&gt; &lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;4.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;分析关联，通过对业务的更深入分析以及各种软件设计原则及性能方面的权衡，明确关联的方向或者去掉一些不需要的关联；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;5.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;找出聚合边界及聚合根，这是一件很有难度的事情；因为你在分析的过程中往往会碰到很多模棱两可的难以清晰判断的选择问题，所以，需要我们平时一些分析经验的积累才能找出正确的聚合根；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;6.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;为聚合根配备仓储，一般情况下是为一个聚合分配一个仓储，此时只要设计好仓储的接口即可；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;7.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;走查场景，确定我们设计的领域模型能够有效地解决业务需求；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;8.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;考虑如何创建领域实体或值对象，是通过工厂还是直接通过构造函数；&lt;/span&gt; &lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;9.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;停下来重构模型。寻找模型中觉得有些疑问或者是蹩脚的地方，比如思考一些对象应该通过关联导航得到还是应该从仓储获取？聚合设计的是否正确？考虑模型的性能怎样，等等；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;领域建模是一个不断重构，持续完善模型的过程，大家会在讨论中将变化的部分反映到模型中，从而是模型不断细化并朝正确的方向走。领域建模是领域专家、设计人员、开发人员之间沟通交流的过程，是大家工作和思考问题的基础。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;在分层架构中其他层如何与领域层交互&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;从经典的领域驱动设计分层架构中可以看出，领域层的上层是应用层，下层是基础设施层。那么领域层是如何与其它层交互的呢？&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;对于会影响领域层中领域对象状态的应用层功能，一般应用层会先启动一个工作单元，然后工作单元会启动一个事务，然后：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;1）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;对于修改领域对象的情况，通过仓储获取领域对象，调用领域对象的相关业务方法以完成业务逻辑处理；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;2）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;对于新增领域对象的情况，通过构造函数或工厂创建出领域对象，如果需要还可以继续对该新创建的领域对象做一些操作，然后把该新创建的领域对象添加到仓储中；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;3）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;对于删除领域对象的情况，可以先把领域对象从仓储中取出来，然后将其从仓储中删除，也可以直接传递一个要删除的领域对象的唯一标识给仓储通知其移除该唯一标识对应领域对象；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;4）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;如果一个业务逻辑涉及到多个领域对象，则调用领域层中的相关领域服务完成操作；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt"&gt;&lt;span style="font-family:宋体;"&gt;注意，以上所说的所有领域对象都是只聚合根，另外在应用层需要获取仓储接口以及领域服务接口时，都可以通过&lt;/span&gt;IOC&lt;span style="font-family:宋体;"&gt;容器获取。最后通知工作单元提交事务从而将所有相关的领域对象的状态以事务的方式持久化到数据库；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt"&gt;&lt;span style="font-family:宋体;"&gt;关于工作单元的实现，具有所知有以下几种方法：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;1）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;基于快照的实现，即领域对象被取出来后，会先保存一个备份的对象，然后当在做持久化操作时，将最新的对象的状态和备份的对象的状态进行比较，如果不相同，则认为有做过修改，然后进行持久化；这种设计的好处是对象不用告诉工作单元自己的状态修改了，而缺点也是显而易见的，那就是性能可能会低，备份对象以及比较对象的状态是否有修改的过程在当对象本身很复杂的时候，往往是一个比较耗时的步骤，而且要真正实现对象的深拷贝以及判断属性是否修改还是比较困难的；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;2）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;不基于快照，而是仓储的相关更新或新增或删除接口被调用时，仓储通知工作单元某个对象被新增了或更新了或删除了。这样工作单元在做数据持久化时也同样可以知道需要持久化哪些对象了；这种方法理论上不需要&lt;/span&gt;ORM&lt;span style="font-family:宋体;"&gt;框架的支持，对领域模型也没有任何倾入性，同时也很好的支持了工作单元的模式。对于不想用高级&lt;/span&gt;ORM&lt;span style="font-family:宋体;"&gt;框架的朋友来说，这种方法挺好；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;3）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;不基于快照，也不用仓储告诉工作单元数据更改了。而是采用&lt;/span&gt;AOP&lt;span style="font-family:宋体;"&gt;的思想，采用透明代理的方式进行一个拦截。在&lt;/span&gt;NHibernate&lt;span style="font-family:宋体;"&gt;中，我们的属性通常要被声明为&lt;/span&gt;virtual&lt;span style="font-family:宋体;"&gt;的，一个原因就是&lt;/span&gt;NHibernate&lt;span style="font-family:宋体;"&gt;会生成一个透明代理，用于拦截对象的属性被修改时，自动通知工作单元对象的状态被更新了。这样工作单元也同样知道需要持久化哪些对象了。这种方法对领域模型的倾入性不大，并且能很好的支持工作单元模式，如果用&lt;/span&gt;NHibernate&lt;span style="font-family:宋体;"&gt;作为&lt;/span&gt;ORM&lt;span style="font-family:宋体;"&gt;，这种方法用的比较多；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:36.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;4）&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;一般是微软用的方法，那就是让领域对象实现&lt;/span&gt;.NET&lt;span style="font-family:宋体;"&gt;框架中的&lt;/span&gt;INotifiyPropertyChanged&lt;span style="font-family:宋体;"&gt;接口，然后在每个属性的&lt;/span&gt;set&lt;span style="font-family:宋体;"&gt;方法的最后一行调用&lt;/span&gt;OnPropertyChanged&lt;span style="font-family:宋体;"&gt;的方法从而显示地通知别人自己的状态修改了。这种方法相对来说对领域模型的倾入性最强。&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;对于不会影响领域层中领域对象状态的查询功能，可以直接通过仓储查询出所需要的数据。但一般领域层中的仓储提供的查询功能也许不能满足界面显示的需要，则可能需要多次调用不同的仓储才能获取所需要显示的数据；其实针对这种查询的情况，我在后面会讲到可以直接通过&lt;/span&gt;CQRS&lt;span style="font-family:宋体;"&gt;的架构来实现。即对于查询，我们可以在应用层不调用领域层的任何东西，而是直接通过某个其他的用另外的技术架构实现的查询引擎来完成查询，比如直接通过构造参数化&lt;/span&gt;SQL&lt;span style="font-family:宋体;"&gt;的方式从数据库一个表或多个表中查询出任何想要显示的数据。这样不仅性能高，也可以减轻领域层的负担。领域模型不太适合为应用层提供各种查询服务，因为往往界面上要显示的数据是很多对象的组合信息，是一种非对象概念的信息，就像报表；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;为什么面向对象比面向过程更能适应业务变化&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;对象将需求用类一个个隔开，就像用储物箱把东西一个个封装起来一样，需求变了，分几种情况，最严重的是大变，那么每个储物箱都要打开改，这种方法就不见得有好处；但是这种情况发生概率比较小，大部分需求变化都是局限在一两个储物箱中，那么我们只要打开这两个储物箱修改就可以，不会影响其他储物柜了。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;而面向过程是把所有东西都放在一个大储物箱中，修改某个部分以后，会引起其他部分不稳定，一个&lt;/span&gt;BUG&lt;span style="font-family:宋体;"&gt;修复，引发新的无数&lt;/span&gt;BUG&lt;span style="font-family:宋体;"&gt;，最后程序员陷入焦头烂额，如日本东京电力公司员工处理核危机一样，心力交瘁啊。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;所以，我们不能粗粒度看需求变，认为需求变了，就是大范围变，万事万物都有边界，老子说，无欲观其缴，什么事物都要观察其边界，虽然需求可以用&lt;/span&gt;&amp;#8220;&lt;span style="font-family:宋体;"&gt;需求&lt;/span&gt;&amp;#8221;&lt;span style="font-family:宋体;"&gt;这个名词表达，谈到需求变了，不都意味着最大边界范围的变化，这样看问题容易走极端。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;其实就是就地画圈圈&lt;/span&gt;&amp;#8212;&amp;#8212;&lt;span style="font-family:宋体;"&gt;边界。我们小时候写作文分老三段也是同样道理，各自职责明确，划分边界明确，通过过渡句实现承上启下&lt;/span&gt;&amp;#8212;&amp;#8212;&lt;span style="font-family:宋体;"&gt;接口。为什么组织需要分不同部门，同样是边界思维。画圈圈容易，但如何画才难，所以&lt;/span&gt;OO&lt;span style="font-family:宋体;"&gt;中思维非常重要。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;需求变化所引起的变化是有边界，若果变化的边界等于整个领域，那么已经是完全不同的项目了。要掌握边界，是需要大量的领域知识的。否则，走进银行连业务职责都分不清的，如何画圈圈呢？&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;面向过程是无边界一词的（就算有也只是最大的边界），它没有要求各自独立，它可以横跨边界进行调用，这就是容易引起&lt;/span&gt;BUG&lt;span style="font-family:宋体;"&gt;的原因，引起&lt;/span&gt;BUG&lt;span style="font-family:宋体;"&gt;不一定是技术错误，更多的是逻辑错误。分别封装就是画圈圈了，所有边界都以接口实现。不用改或者小改接口，都不会牵一发动全身。若果面向过程中考虑边界，那么也就已经上升到&lt;/span&gt;OO&lt;span style="font-family:宋体;"&gt;思维，即使用的不是对象语言，但对象已经隐含其中。说白了，面向对象与面向过程最大区别就是：分解。边界的分解。从需求到最后实现都贯穿。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;面向对象的实质就是边界划分，封装，不但对需求变化能够量化，缩小影响面；因为边界划分也会限制出错的影响范围，所以&lt;/span&gt;OO&lt;span style="font-family:宋体;"&gt;对软件后期&lt;/span&gt;BUG&lt;span style="font-family:宋体;"&gt;等出错也有好处。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;软件世界永远都有&lt;/span&gt;BUG,BUG&lt;span style="font-family:宋体;"&gt;是清除不干净的，就像人类世界永远都存在不完美和阴暗面，问题关键是：上帝用空间和时间的边界把人类世界痛苦灾难等不完美局限在一个范围内；而软件世界如果你不采取&lt;/span&gt;OO&lt;span style="font-family:宋体;"&gt;等方法进行边界划分的话，一旦出错，追查起来情况会有多糟呢？&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;/div&gt;&lt;p&gt;&lt;span style="font-family:宋体;"&gt;软件世界其实类似人类现实世界，有时出问题了，探究原因一看，原来是两个看上去毫无联系的因素导致的，古人只好经常求神拜佛，我们程序员在自己的软件上线运行时，大概心里也在求神拜佛别出大纰漏，如果我们的软件采取&lt;/span&gt;OO&lt;span style="font-family:宋体;"&gt;封装，我们就会坦然些，肯定会出错，但是我们已经预先划定好边界，所以，不会产生严重后果，甚至也不会出现难以追查的魔鬼&lt;/span&gt;BUG&lt;span style="font-family:宋体;"&gt;。&lt;/span&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;领域驱动设计的其他一些主题&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;上面只是涉及到&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中最基本的内容，&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中还有很多其他重要的内容在上面没有提到，如：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;1.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;模型上下文、上下文映射、上下文共享；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;2.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;如何将分析模式和设计模式运用到&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;3.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;一些关于柔性设计的技巧；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;4.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;如果保持模型完整性，以及持续集成方面的知识；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;5.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;如何精炼模型，识别核心模型以及通用子领域；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;&lt;span&gt;6.&lt;span style="font:7.0pt &amp;quot;Times New Roman&amp;quot;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&amp;#8230;&amp;#8230;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;这些主题都很重要，因为篇幅有限以及我目前掌握的知识也有限，并且为了突出这篇文章的重点，所以不对他们做详细介绍了，大家有兴趣的可以自己阅读一下。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span  style="font-family: 宋体; "&gt;一些相关的扩展阅读&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;CQRS&lt;span style="font-family:宋体;"&gt;架构：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;核心思想是将应用程序的查询部分和命令部分完全分离，这两部分可以用完全不同的模型和技术去实现。比如命令部分可以通过领域驱动设计来实现；查询部分可以直接用最快的非面向对象的方式去实现，比如用&lt;/span&gt;SQL&lt;span style="font-family:宋体;"&gt;。这样的思想有很多好处：&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;1）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;实现命令部分的领域模型不用经常为了领域对象可能会被如何查询而做一些折中处理；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;2）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;由于命令和查询是完全分离的，所以这两部分可以用不同的技术架构实现，包括数据库设计都可以分开设计，每一部分可以充分发挥其长处；&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left:18.0pt;text-indent:-18.0pt;"&gt;&lt;span&gt;3）&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:宋体;"&gt;高性能，命令端因为没有返回值，可以像消息队列一样接受命令，放在队列中，慢慢处理；处理完后，可以通过异步的方式通知查询端，这样查询端可以做数据同步的处理；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Event Sourcing&lt;span style="font-family:宋体;"&gt;：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;基于&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;的设计，对于聚合，不保存聚合的当前状态，而是保存对象上所发生的每个事件。当要重建一个聚合对象时，可以通过回溯这些事件（即让这些事件重新发生）来让对象恢复到某个特定的状态；因为有时一个聚合可能会发生很多事件，所以如果每次要在重建对象时都从头回溯事件，会导致性能低下，所以我们会在一定时候为聚合创建一个快照。这样，我们就可以基于某个快照开始创建聚合对象了。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;DCI&lt;span style="font-family:宋体;"&gt;架构：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;DCI&lt;span style="font-family:宋体;"&gt;架构强调，软件应该真实的模拟现实生活中对象的交互方式，代码应该准确朴实的反映用户的心智模型。在&lt;/span&gt;DCI&lt;span style="font-family:宋体;"&gt;中有：数据模型、角色模型、以及上下文这三个概念。数据模型表示程序的结构，目前我们所理解的&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中的领域模型可以很好的表示数据模型；角色模型表示数据如何交互，一个角色定义了某个&amp;#8220;身份&amp;#8221;所具有的交互行为；上下文对应业务场景，用于实现业务用例，注意是业务用例而不是系统用例，业务用例只与业务相关；软件运行时，根据用户的操作，系统创建相应的场景，并把相关的数据对象作为场景参与者传递给场景，然后场景知道该为每个对象赋予什么角色，当对象被赋予某个角色后就真正成为有交互能力的对象，然后与其他对象进行交互；这个过程与现实生活中我们所理解的对象是一致的；&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;DCI&lt;span style="font-family:宋体;"&gt;的这种思想与&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中的领域服务所做的事情是一样的，但实现的角度有些不同。&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中的领域服务被创建的出发点是当一些职责不太适合放在任何一个领域对象上时，这个职责往往对应领域中的某个活动或转换过程，此时我们应该考虑将其放在一个服务中。比如资金转帐的例子，我们应该提供一个资金转帐的服务，用来对应领域中的资金转帐这个领域概念。但是领域服务内部做的事情是协调多个领域对象完成一件事情。因此，在&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中的领域服务在协调领域对象做事情时，领域对象往往是处于一个被动的地位，领域服务通知每个对象要求其做自己能做的事情，这样就行了。这个过程中我们似乎看不到对象之间交互的意思，因为整个过程都是由领域服务以面向过程的思维去实现了。而&lt;/span&gt;DCI&lt;span style="font-family:宋体;"&gt;则通用引入角色，赋予角色以交互能力，然后让角色之间进行交互，从而可以让我们看到对象与对象之间交互的过程。但前提是，对象之间确实是在交互。因为现实生活中并不是所有的对象在做交互，比如有&lt;/span&gt;A&lt;span style="font-family:宋体;"&gt;、&lt;/span&gt;B&lt;span style="font-family:宋体;"&gt;、&lt;/span&gt;C&lt;span style="font-family:宋体;"&gt;三个对象，&lt;/span&gt;A&lt;span style="font-family:宋体;"&gt;通知&lt;/span&gt;B&lt;span style="font-family:宋体;"&gt;做事情，&lt;/span&gt;A&lt;span style="font-family:宋体;"&gt;通知&lt;/span&gt;C&lt;span style="font-family:宋体;"&gt;做事情，此时可以认为&lt;/span&gt;A&lt;span style="font-family:宋体;"&gt;和&lt;/span&gt;B&lt;span style="font-family:宋体;"&gt;，&lt;/span&gt;A&lt;span style="font-family:宋体;"&gt;和&lt;/span&gt;C&lt;span style="font-family:宋体;"&gt;之间是在交互，但是&lt;/span&gt;B&lt;span style="font-family:宋体;"&gt;和&lt;/span&gt;C&lt;span style="font-family:宋体;"&gt;之间没有交互。所以我们需要分清这种情况。资金转帐的例子，&lt;/span&gt;A&lt;span style="font-family:宋体;"&gt;相当于转帐服务，&lt;/span&gt;B&lt;span style="font-family:宋体;"&gt;相当于帐号&lt;/span&gt;1&lt;span style="font-family:宋体;"&gt;，&lt;/span&gt;C&lt;span style="font-family:宋体;"&gt;相当于帐号&lt;/span&gt;2&lt;span style="font-family:宋体;"&gt;。因此，资金转帐这个业务场景，用领域服务比较自然。有人认为&lt;/span&gt;DCI&lt;span style="font-family:宋体;"&gt;可以替换&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;中的领域服务，我持怀疑态度。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;四色原型分析模式：&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;line-height:15.0pt;word-break:break-all"&gt;&lt;strong&gt;&lt;span&gt;1） &lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;时刻&lt;/span&gt;-&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;时间段原型（&lt;/span&gt;&lt;span&gt;Moment-Interval Archetype&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;）&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;line-height:15.0pt;word-break:break-all"&gt;&lt;span style="font-family: 宋体;"&gt;表示在某个时刻或某一段时间内发生的某个活动。使用粉红色表示，简写为&lt;/span&gt;MI&lt;span style="font-family:宋体;"&gt;。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;line-height:15.0pt;word-break:break-all"&gt;&lt;strong&gt;&lt;span&gt;2） &lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;参与方&lt;/span&gt;-&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;地点&lt;/span&gt;-&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;物品原型（&lt;/span&gt;Part-Place-Thing Archetype&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;）&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;line-height:15.0pt;word-break:break-all"&gt;&lt;span style="font-family: 宋体;"&gt;表示参与某个活动的人或物，地点则是活动的发生地。使用绿色表示。简写为&lt;/span&gt;PPT&lt;span style="font-family:宋体;"&gt;。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;line-height:15.0pt;word-break:break-all"&gt;&lt;strong&gt;&lt;span&gt;3） &lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;描述原型（&lt;/span&gt;Description Archetype&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;）&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;line-height:15.0pt;word-break:break-all"&gt;&lt;span style="font-family: 宋体;"&gt;表示对&lt;/span&gt;PPT&lt;span style="font-family:宋体;"&gt;的本质描述。它不是&lt;/span&gt;PPT&lt;span style="font-family:宋体;"&gt;的分类！&lt;/span&gt;Description&lt;span style="font-family:宋体;"&gt;是从&lt;/span&gt;PPT&lt;span style="font-family:宋体;"&gt;抽象出来的不变的共性的属性的集合。使用蓝色表示，简写为&lt;/span&gt;DESC&lt;span style="font-family:宋体;"&gt;。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;line-height:15.0pt;word-break:break-all"&gt;&lt;span style="font-family: 宋体;"&gt;举个例子，有一个人叫张三，如果某个外星人问你张三是什么？你会怎么说？可能会说，张三是个人，但是外星人不知道&amp;#8220;人&amp;#8221;是什么。然后你会怎么办？你就会说：张三是个由一个头、两只手、两只脚，以及一个身体组成的客观存在。虽然这时外星人仍然不知道人是什么，但我已经可以借用这个例子向大家说明什么是&amp;#8220;&lt;/span&gt;Description&lt;span style="font-family:宋体;"&gt;&amp;#8221;了。在这个例子中，张三就是一个&lt;/span&gt;PPT&lt;span style="font-family:宋体;"&gt;，而&amp;#8220;由一个头、两只手、两只脚，以及一个身体组成的客观存在&amp;#8221;就是对张三的&lt;/span&gt;Description&lt;span style="font-family:宋体;"&gt;，头、手、脚、身体则是人的本质的不变的共性的属性的集合。但我们人类比较聪明，很会抽象总结和命名，已经把这个&lt;/span&gt;Description&lt;span style="font-family:宋体;"&gt;用一个字来代替了，那就是&amp;#8220;人&amp;#8221;。所以就有所谓的张三是人的说法。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="margin-left:18.0pt;text-align:left; text-indent:-18.0pt;line-height:15.0pt;word-break:break-all"&gt;&lt;strong&gt;&lt;span&gt;4） &lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;角色原型（&lt;/span&gt;Role Archetype&lt;/strong&gt;&lt;strong&gt;&lt;span style="font-family:宋体;"&gt;）&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;line-height:15.0pt;word-break:break-all"&gt;&lt;span style="font-family: 宋体;"&gt;角色就是我们平时所理解的&amp;#8220;身份&amp;#8221;。使用黄色表示，简写为&lt;/span&gt;Role&lt;span style="font-family:宋体;"&gt;。为什么会有角色这个概念？因为有些活动，只允许具有特定角色（身份）的&lt;/span&gt;PPT&lt;span style="font-family:宋体;"&gt;（参与者）才能参与该活动。比如一个人只有具有教师的角色才能上课（一种活动）；一个人只有是一个合法公民才能参与选举和被选举；但是有些活动也是不需要角色的，比如一个人不需要具备任何角色就可以睡觉（一种活动）。当然，其实说人不需要角色就能睡觉也是错误的，错在哪里？因为我们可以这样理解：一个客观存在只要具有&amp;#8220;人&amp;#8221;的角色就能睡觉，其实这时候，我们已经把&lt;/span&gt;DESC&lt;span style="font-family:宋体;"&gt;当作角色来看待了。所以，其实角色这个概念是非常广的，不能用我们平时所理解的狭义的&amp;#8220;身份&amp;#8221;来理解，因为&amp;#8220;教师&amp;#8221;、&amp;#8220;合法公民&amp;#8221;、&amp;#8220;人&amp;#8221;都可以被作为角色来看待。因此，应该这样说：任何一个活动，都需要具有一定角色的参与者才能参与。&lt;/span&gt;&lt;/p&gt;  &lt;p align="left" style="text-align:left;line-height:15.0pt;word-break:break-all"&gt;&lt;span style="font-family: 宋体;"&gt;用一句话来概括四色原型就是：一个什么什么样的人或组织或物品以某种角色在某个时刻或某段时间内参与某个活动。&lt;/span&gt; &lt;span style="font-family:宋体;"&gt;其中&amp;#8220;什么什么样的&amp;#8221;就是&lt;/span&gt;DESC&lt;span style="font-family:宋体;"&gt;，&amp;#8220;人或组织或物品&amp;#8221;就是&lt;/span&gt;PPT&lt;span style="font-family:宋体;"&gt;，&amp;#8220;角色&amp;#8221;就是&lt;/span&gt;Role&lt;span style="font-family:宋体;"&gt;，而&amp;#8221;某个时刻或某段时间内的某个活动&lt;/span&gt;"&lt;span style="font-family:宋体;"&gt;就是&lt;/span&gt;MI&lt;span style="font-family:宋体;"&gt;。&lt;/span&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:宋体;"&gt;以上这些东西如果在学习了&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;之后再去学习会对&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;有更深入的了解，但我觉得&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;相对比较基础，如果我们在已经了解了&lt;/span&gt;DDD&lt;span style="font-family:宋体;"&gt;的基础之上再去学习这些东西会更加有效和容易掌握。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;希望本文对大家有所帮助。&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2204949.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/09/18/2180656.html</id><title type="text">分享我的面向对象分析方法</title><summary type="text">先说最重要东西，即我的核心面向对象分析思路：1）找出最关键的一些业务场景；一般通过动词来寻找，比如招聘系统中，一个应聘人投递一个职位就是一次应聘，应聘就是一个业务场景；一个学生参加某门课的考试，那么考试就是一个业务场景；一个学生去图书馆借书，那么借书就是一个业务场景；2）针对每个业务场景分析出有哪些场景参与者，哪些参与者以对象的形式参与，哪些参与者以服务的形式参与；为什么要区分对象还是服务是因为有时候我们不关心参与者是哪个，而只关心参与者是什么。一般服务在系统中我们只关心它是什么服务，并且在系统中服务一般也只有一个实例；而对象则不同，我们会关心对象是谁，即哪一个；3）分析每个场景参与者对象的基</summary><published>2011-09-18T13:10:00Z</published><updated>2011-09-18T13:10:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/09/18/2180656.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/09/18/2180656.html"/><content type="html">&lt;p&gt;&lt;u&gt;先说最重要东西，即我的核心面向对象分析思路：&lt;/u&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1）找出最关键的一些业务场景；&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;一般通过动词来寻找，比如招聘系统中，一个应聘人投递一个职位就是一次应聘，应聘就是一个业务场景；一个学生参加某门课的考试，那么考试就是一个业务场景；一个学生去图书馆借书，那么借书就是一个业务场景；&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2）针对每个业务场景分析出有哪些场景参与者，哪些参与者以对象的形式参与，哪些参与者以服务的形式参与；&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;为什么要区分对象还是服务是因为有时候我们不关心参与者是哪个，而只关心参与者是什么。一般服务在系统中我们只关心它是什么服务，并且在系统中服务一般也只有一个实例；而对象则不同，我们会关心对象是谁，即哪一个；&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3）分析每个场景参与者对象的基本状态特征；&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;所谓的基本状态特征是指对象与生俱来的，对象从一开始被创建出来之后就具有的状态特征；最形象的例子就是人的身高体重，当人一出生便具有了身高和体重这两个状态特征；再比如一篇博文，它从被写好之时起就具有了内容这个状态特征，但是我们可以随便修改博文的内容；但是有些状态特征是不能修改的，比如博文的创建时间一旦博文被创建之后便不能再被修改；需要注意的是我们不要把和对象关联的一些关联信息也认为是对象的基本状态特征。比如某人有一本英语六级考试证书，那么人和证书之间的关系是拥有的关系，证书不是人固有的与生俱来的基本状态特征，而是人参与了某次考试这个场景后得来的；后面我会提到这种关联关系该如何去思考和理解！&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4）分析&lt;/strong&gt;&lt;strong&gt;每个场景参与者对象分别扮演什么角色参与场景，&lt;/strong&gt;&lt;strong&gt;整个场景的完整交互&lt;/strong&gt;&lt;strong&gt;过程是怎样的，对象&lt;/strong&gt;&lt;strong&gt;在参与场景的过程中执行了哪些交互行为&lt;/strong&gt;&lt;strong&gt;；&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;相信大家都明白这点非常重要，因为它涉及到对象之间如何交互，涉及到该如何分析哪个对象该具有哪个交互职责；从而最终决定了在代码级别哪个类该具有哪些方法的问题。关于这方面思考的例子我会在下面进行介绍，这里先说一下理论吧。我觉得要点是将整个业务场景中的每个交互行为通过四色原型的分析方法来理解。&lt;span  style="line-height: 18px; "&gt;&lt;strong&gt;用一句话来概括四色原型就是：一个什么什么样的人或组织或物品以某种角色在某个时刻或某段时间内参与某个活动。&lt;/strong&gt;&lt;/span&gt;&lt;span  style="line-height: 18px; "&gt;另外一个技巧就是，我们经常可以问自己，这个交互行为是&amp;#8220;谁通知谁做什么事情？&amp;#8220;，行为的驱动者是谁？行为的执行者是谁？一般行为的驱动者就是通知方，行为的执行者就是被通知方，被通知方拥有&amp;#8221;通知方要求做的事情&amp;#8220;执行行为；另外，我觉得还需要说明的是，现实生活中的对象并不是说其扮演了某个角色后才具有角色所定义的行为的，而是本来就有的，只不过是在扮演角色后表现出了该行为；所以对于现实生活中的对象，执行角色所定义的行为和扮演角色是同时发生的，没有谁先谁后的说法；但是软件中的对象则不同，因为软件中的对象只是现实生活中的对象的某一个我们所关心的方面，所以它的能力也有限。另外从设计实现的角度职责单一的角度来说，我们也不会将软件中的对象设计的很复杂，包含很多职责，因为这样会导致对象难以维护，这样做虽不违背分析原则，但违背设计原则。软件中的对象我们往往是设计成当它扮演某个角色时，动态给对象注入角色所定义的交互行为，从而给对象赋予了参与场景交互的能力。因此简单的说，软件中的对象，平时只具有基本的状态特征和基本的非交互行为，而当它扮演某个角色时，则动态具有交互行为；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;5）分析交互过程结束后分别会对每个场景参与者对象产生哪些基本状态特征的改变；&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个很好理解，当一个对象参与了某个交互活动后，一些基本状态特征会发生改变，比如一个人参加一次100米跑步比赛后，心跳速度会加快；心跳速度就是人的基本体征；这个应该很好理解吧，不多举例了。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;6）分析如何记录和跟踪这一次交互行为，分析这次交互行为会产生哪些额外的信息；&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这点估计大家平时很少思考，而这点我想也正是我的面向对象分析思路最具特色的地方吧！大家一定知道，一次对象的交互活动会产生一些与该交互活动相关的交互信息。比如一次应聘活动会产生一些与该活动相关的信息，如是否录取，笔试成绩，面试成绩等；比如一次考试会产生考试成绩这个信息；一次借书会产生一个借阅信息（包含：借书人、被借的书、借书时间，我们可能还会设计一个还书时间）；并且，在很多情况下，这些交互信息会在后续的其他交互场景中再被更新。比如，一次应聘一开始状态可能是&amp;#8221;新投递&amp;#8220;，表示应聘人刚刚投了简历并选了某个职位，后来她去参加笔试或面试了，那么这次应聘的状态就变为了&amp;#8221;已笔试&amp;#8220;或&amp;#8221;已面试&amp;#8220;；在比如一个学生参加一次考试，刚开始还没有成绩，但后来老师批卷子后便有了考试成绩。再比如一次借书后，如果这本书还没被还，则还书时间为空，而一旦还书了之后，便有了还书时间；因此，我们从这些规律中可以发现，交互其实是一个过程，并且该过程一旦开始后就会产生一些相关的信息，如应聘的状态，考试的成绩，借阅信息的归还时间，等等。通常我们会把交互过程本身所涉及的一切信息以及交互过程所产生的所有附加信息作为一个整体来进行考虑。所以，我觉得我们有必要设计一个对象，用来表示某一次交互的结果，这个结果包含交互过程本身所涉及的一切信息以及交互过程所产生的所有附加信息；大家想想，看到&amp;#8221;应聘&amp;#8220;这个单词，你有时候会认为它是一个动词，优势后会认为它是一个名词。在认为是动词时，我们关注的是交互本身，活动本身，强调行为；而在认为是名词时，我们关注的是应聘行为所产生的一切信息；所以，看到这里，我想大家应该心里有个数了，就是在交互行为结束后，我们往往需要设计一个对象用来表示一次交互活动的相关信息；这些信息一方面体现了交互活动的参与者，（交互时间，交互地点，如果我们关心这些的话），另一方面体现了交互活动所产生的附加的信息，如成绩，应聘状态，借书还书时间，等等。最后，需要强调的是这些信息之所以设计为对象是因为这些信息不是历史，即不是不可改变的，相反，这些信息会在后续的其他交互活动中被更新；所以，看到这里，我想我们就不用在纠结对象在参加交互活动后所产生的一些与它关联的信息该如何存放这个问题了。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;好了，上面就是我所掌握的面向对象分析思路。下面以图书借阅系统（&lt;a href="http://files.cnblogs.com/netfocus/BookLibraryExample.rar" target="_blank"&gt;点击这里下载源代码&lt;/a&gt;）为例，按照上面的分析方法进行分析。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;u&gt;先简单描述一下我所说的图书借阅系统的主要业务场景：&lt;/u&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;图书信息入库场景：&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;图书馆管理员扫描不同名称的书本。大家都知道每本具体的书都有一个ISBN，即International Standard Book Number，国际标注书号。图书馆是根据ISBN来管理书本的，同一个ISBN的书会有很多不同的副本，每一个副本就是一本实实在在的书。所以，严格的说图书馆数据库中保存的是&amp;#8220;书本的库存信息&amp;#8221;。在图书入库的场景中，只要是ISBN相同，即书名相同的书只会被扫描一次，然后管理员会输入这种书总共有多少本，应该放在什么地方等库存信息。当然这只是我自己理解的业务场景，姑且不论对错，咱们就先当这个理解是正确的吧。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;借书场景：&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;借书人持图书卡去图书馆，先找到几本要借的书，然后跑到借书处借书；&lt;/li&gt;&lt;li&gt;图书管理员扫描借书人的借书卡以及书本的条形码，条形码就是ISBN；&lt;/li&gt;&lt;li&gt;借书人拿着书从图书馆离开；&lt;/li&gt;&lt;/ol&gt;&lt;strong&gt;还书场景：&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;借书人吃图书卡去图书馆，到还书处还书；&lt;/li&gt;&lt;li&gt;图书管理员扫描还书人的借书卡以及书本的条形码，如果有需要罚款的，也在此时会计算出来；&lt;/li&gt;&lt;li&gt;还书人离开图书馆；&lt;/li&gt;&lt;/ol&gt;&lt;hr /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;u&gt;接下来开始对每个场景按照上面的分析思路进行分析。&lt;/u&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;图书入库场景的分析：&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;1）场景参与者：&amp;nbsp;&lt;/p&gt;&lt;p&gt;图书馆、书本；其中图书馆在整个图书借阅系统中只需要一个实例，我们也不关心是这个图书馆还是那个图书馆，所以我觉得可以把图书馆设计为一个服务。&lt;/p&gt;&lt;p&gt;2）参与者基本状态特征：&lt;/p&gt;&lt;p&gt;书本的基本状态特征：如书名、作者、出版社等信息；&lt;/p&gt;&lt;p&gt;图书馆的基本状态特征：没有，一般情况下服务是无状态的，服务只提供服务行为；&lt;/p&gt;&lt;p&gt;3）场景交互过程分析：&lt;/p&gt;&lt;p&gt;很容易理解，图书馆本身就具有图书入库的行为。图书入库时，图书馆服务会生成并保存一个书本的&amp;#8220;库存信息&amp;#8221;，该信息包含了某个名称的书本的数量、书架位置信息。该库存信息中的Count表示某个名称的书有几本。当在借书或还书的场景发生时，这个Count就会改变；&amp;nbsp;代码示例如下：&lt;/p&gt;&lt;p&gt;图书入库场景类的实现：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;StoreBookContext&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ILibraryService&amp;nbsp;library&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Book&amp;nbsp;book&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;StoreBookContext(ILibraryService&amp;nbsp;library,&amp;nbsp;Book&amp;nbsp;book)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;.library&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;library;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;.book&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;book;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Interaction(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;count,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;location)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;library.StoreBook(book,&amp;nbsp;count,&amp;nbsp;location);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;图书馆图书入库的方法：&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;StoreBook(Book&amp;nbsp;book,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;count,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;location)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;图书入库时生成图书的库存信息&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;bookStoreInfo&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;BookStoreInfo(book,&amp;nbsp;count);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bookStoreInfo.Location&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;location;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bookStoreInfoRepository.Add(bookStoreInfo);&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;4）交互之后，场景参与者的基本状态特征是否发生变化？都没有发生变化。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;借书场景分析：&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div&gt;&lt;p&gt;1）场景参与者：&amp;nbsp;&lt;/p&gt;&lt;p&gt;图书馆注册帐号、图书馆、书本；图书馆是一个服务、书本也只是一本普通的书，它没有行为，它是被借的。需要着重分析的是图书馆注册帐号这个参与者。先说一下我对：软件使用者（即软件的用户）、注册帐号、图书卡、借书人这四个概念的理解。理解这些概念非常重要！首先，软件使用者就是软件的用户，就是我们平时所说的用户，这点没什么问题。图书卡和注册帐号的关系是什么？我们都知道现实生活中，人持图书卡去借书；而软件中，人通过其注册帐号登录，然后以该注册帐号所代表的&amp;#8220;人&amp;#8221;做事情；因此，图书卡是用户用来借书的工具；同样注册帐号也是软件用户通过软件进行借书的工具；用户拥有图书卡，用户拥有注册帐号。那么借书人如何理解呢？我们平时所说的借书人其实就是一种角色，即用户在通过借书卡参与借书的行为过程中，我们把正在执行该行为或已经执行了该行为的人叫做借书人。用更通用的表达方式就是，我们通常会给正在做某件事情或已经做了某件事情的参与者一个称谓，如凶手、借书人、还书人、应聘人，等等；所以，有了这些理解之后，我们就知道借书人只是一个角色，某个注册帐号扮演了借书人这个角色后可以行驶借书的行为；&lt;/p&gt;&lt;p&gt;2）参与者基本状态特征：&lt;/p&gt;&lt;p&gt;书本的基本状态特征：如书名、作者、出版社等信息；&lt;/p&gt;&lt;p&gt;图书馆的基本状态特征：没有，一般情况下服务是无状态的，服务只提供服务行为；&lt;/p&gt;&lt;p&gt;注册帐号的基本状态：图书馆注册帐号有基本的状态特征，比如：卡号，所有者姓名，是否锁定，等等；&lt;/p&gt;&lt;p&gt;3）场景交互过程分析：&lt;/p&gt;&lt;p&gt;某个软件的使用者，即软件用户通过某个已注册帐号登录软件系统，然后选择了几本想借的书之后点击&amp;#8220;借书&amp;#8221;按钮，然后该按钮触发一个借书的场景，该场景创建时包含了部分的场景参与者，在借书这个例子中就是帐号和书，然后借书场景知道帐号应该扮演借书者这个角色。所以帐号在扮演了借书者这个角色后对每一本书行驶借书的交互行为。扮演了借书者角色的注册帐号自动具有了借书的行为，在该行为的内部实现中，通知图书馆把书借出来。随后图书馆接到通知后，首先根据当前书本获取书本的库存信息，如果当前库存信息是0本，说明这本书没有库存，就抛出异常通知软件使用者这本书目前已经被借光了。如果还有库存，则先更新库存信息，比如图书的数量减1，然后根据当前借书人，书本，以及当前时间生成一个借书信息对象，该对象还会包含一个图书归还时间的附加信息。最后将该借书信息对象保存起来。代码示例如下：&lt;/p&gt;&lt;p&gt;借书场景类的实现：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;BorrowBooksContext&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;LibraryAccount&amp;nbsp;account&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Book&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;BorrowBooksContext(LibraryAccount&amp;nbsp;account,&amp;nbsp;IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Book&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;.account&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;account;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;.books&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Interaction()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;borrower&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;account.ActAs&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;IBorrower&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;(var&amp;nbsp;book&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;borrower.BorrowBook(book);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;借阅者的借书方法：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;BorrowBook(Book&amp;nbsp;book)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;通知图书馆把书借给我&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;library.LendBook(book,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;}&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;图书馆借出书的方法：&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;font  color="#0000ff"&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;LendBook(Book&amp;nbsp;book,&amp;nbsp;IBorrower&amp;nbsp;borrower)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;更新书本在图书馆的库存信息，如：数量信息、所在书架位置信息&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;bookStoreInfo&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;bookStoreInfoRepository.GetBookStoreInfo(book.Id);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;(bookStoreInfo.Count&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Exception(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;.Format(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;The&amp;nbsp;count&amp;nbsp;of&amp;nbsp;book&amp;nbsp;'{0}'&amp;nbsp;in&amp;nbsp;library&amp;nbsp;is&amp;nbsp;zero,&amp;nbsp;so&amp;nbsp;you&amp;nbsp;cannot&amp;nbsp;borrow&amp;nbsp;it.&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&amp;nbsp;book.BookName));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bookStoreInfo.DecreaseCount();&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;数量减1&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bookStoreInfo.Location&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;位置清空&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;生成借书信息并保存到Repository中&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;borrowInfoRepository.Add(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;BorrowInfo(book,&amp;nbsp;borrower,&amp;nbsp;DateTime.Now));&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;4）交互之后，场景参与者的基本状态特征是否发生变化？都没有发生变化。&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;还书场景分析：&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;有了借书场景的分析，那么还书场景也很容易分析了，主要的过程是：注册帐号扮演借阅者角色执行还书行为，执行过过程中通知图书馆接收某本要归还的书，图书馆接到通知后首先调出与该书本对应的那一次借书信息，然后更新其还书时间，最后更新图书的库存信息。另外的基本和借书类似了，相信大家一看代码都应该明白了，直接上代码吧！&lt;/p&gt;&lt;p&gt;还书场景类：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ReturnBooksContext&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;LibraryAccount&amp;nbsp;account&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Book&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ReturnBooksContext(LibraryAccount&amp;nbsp;account,&amp;nbsp;IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Book&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;.account&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;account;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;.books&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Interaction()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;returnner&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;account.ActAs&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;IBorrower&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;(var&amp;nbsp;book&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;books)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;returnner.ReturnBook(book);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;借书者的还书方法：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ReturnBook(Book&amp;nbsp;book)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;通知图书馆接收我要归还的书&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;library.ReceiveReturnedBook(book,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;图书馆接收被还的书的方法：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ReceiveReturnedBook(Book&amp;nbsp;book,&amp;nbsp;IBorrower&amp;nbsp;borrower)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;设置借书信息的还书时间&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;borrowedInfo&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;borrowInfoRepository.FindNotReturnedBorrowInfo(borrower.Id,&amp;nbsp;book.Id);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;borrowedInfo.ReturnTime&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;DateTime.Now;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;这里，真正的系统还会计算归还时间是否超期，计算罚款之类的逻辑，因为我这个是一个演示的例子，所以不做这个处理了&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;这里只更新书本的数量信息，因为还书时并不是马上把书本放回书架的，所以此时书本的书架位置信息还是保留为空&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;等到我们将这本书放到书架的某个位置时，才会更新其位置信息&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;bookStoreInfo&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;bookStoreInfoRepository.GetBookStoreInfo(book.Id);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bookStoreInfo.IncreaseCount();&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;数量加1&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;好了，差不多就这样吧，从整理思考到文章写作完成，花了我不少心思和时间那，希望大家都能看明白！另外一个题外话，大家在看我的源代码时，不要过分注重我的框架实现，而应该注重这种面向对象的分析思路，框架是偏设计的，是用来为了更方便的支持由这种分析思路而产生的代码实现。我想你懂的，呵呵！&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2180656.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/09/18/2180656.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/09/16/2179293.html</id><title type="text">分享：基于DDD建模思想、四色原型分析方法，以及DCI架构思想的领域建模基础架构及一个图书借阅系统的演示Demo</title><summary type="text">废话不说了，一切要看了源代码才知道！一句话：这个基础架构和Demo是我用了很多的时间反复思考、重构才做出来的，从代码中你将看到：1）我的编码风格，细微处见功底；2）如何设计一个基于DDD建模思想、四色原型分析方法，以及DCI架构思想的领域建模基础架构；3）展示如何用上面的思想分析和设计一个图书借阅系统的部分核心业务逻辑（借书和还书）；下载地址：http://files.cnblogs.com/netfocus/BookLibraryExample.rar需要用VS2010才能打开。各位看官如果在看完代码后觉得有一些收获，请支持一下；如果有什么批评的建议或意见也务必跟我说，大家多讨论才能进步。今</summary><published>2011-09-16T15:14:00Z</published><updated>2011-09-16T15:14:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/09/16/2179293.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/09/16/2179293.html"/><content type="html">&lt;p&gt;废话不说了，一切要看了源代码才知道！一句话：这个基础架构和Demo是我用了很多的时间反复思考、重构才做出来的，从代码中你将看到：&lt;/p&gt;&lt;p&gt;1）我的编码风格，细微处见功底；&lt;/p&gt;&lt;p&gt;2）如何设计一个&lt;strong&gt;基于DDD建模思想、四色原型分析方法，以及DCI架构思想&lt;/strong&gt;的领域建模基础架构；&lt;/p&gt;&lt;p&gt;3）展示如何用上面的思想分析和设计一个图书借阅系统的&lt;strong&gt;部分核心业务逻辑&lt;/strong&gt;（借书和还书）；&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;下载地址：&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/netfocus/BookLibraryExample.rar" target="_blank"&gt;http://files.cnblogs.com/netfocus/BookLibraryExample.rar&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;需要用VS2010才能打开。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;各位看官如果在看完代码后觉得有一些收获，请支持一下；如果有什么批评的建议或意见也务必跟我说，大家多讨论才能进步。今天没时间写详细的设计思想，在我之前的博文中也基本提到了大概（虽然还有些错误），下回有时间再写吧！&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2179293.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/09/16/2179293.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/netfocus/archive/2011/09/10/2173099.html</id><title type="text">我对什么是真正的对象，以及软件中的对象在分析阶段、设计阶段、实现阶段的一些看法</title><summary type="text">最近对OO的理解又有了一些新的认识，拿出来和大家分享一下。为了能让大家简单直观清晰的知道我想表达的主要意思，我不说废话了。直接提出问题，然后回答。1. 什么是真正的对象？2. 什么是面向对象分析阶段时的对象？3. 什么是面向对象设计阶段时的对象？4. 什么是面向对象实现阶段时的对象？1. 真正的对象：我所理解的真正的对象就是现实生活中客观存在或不存在的真正的对象。这个对象有一个明显的特征就是它具有非常多的状态特征和行为特征。比如一个人是一个对象，他在一生中会经历无数个交互场景，在这个过程中，每个人的行为特征会不断增多，大部分行为是通过后天学习得到的，只有少数行为是先天就具有的；另一方面，对于状</summary><published>2011-09-10T04:08:00Z</published><updated>2011-09-10T04:08:00Z</updated><author><name>netfocus</name><uri>http://www.cnblogs.com/netfocus/</uri></author><link rel="alternate" href="http://www.cnblogs.com/netfocus/archive/2011/09/10/2173099.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/netfocus/archive/2011/09/10/2173099.html"/><content type="html">&lt;p&gt;最近对OO的理解又有了一些新的认识，拿出来和大家分享一下。为了能让大家简单直观清晰的知道我想表达的主要意思，我不说废话了。直接提出问题，然后回答。&lt;/p&gt;&lt;p&gt;1. 什么是真正的对象？&lt;/p&gt;&lt;p&gt;2. 什么是面向对象分析阶段时的对象？&amp;nbsp;&lt;/p&gt;&lt;p&gt;3. 什么是面向对象设计阶段时的对象？&lt;/p&gt;&lt;p&gt;4. 什么是面向对象实现阶段时的对象？&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;1. 真正的对象：&lt;/p&gt;&lt;p&gt;我所理解的真正的对象就是现实生活中客观存在或不存在的真正的对象。这个对象有一个明显的特征就是它具有非常多的状态特征和行为特征。比如一个人是一个对象，他在一生中会经历无数个交互场景，在这个过程中，每个人的行为特征会不断增多，大部分行为是通过后天学习得到的，只有少数行为是先天就具有的；另一方面，对于状态特征也是在时不时的变化，比如你的身高、体重，等等。最后，人因为会参与到不同的交互场景，会导致和他关联的各种关联信息也会不断增多，比如你去上大学，老师给你一张借书卡，此时你就拥有了一张借书卡，可以理解为你多了一个关联信息；哪一天你去参加英语四级考试，考了70分，然后你拥有了一本四级考试证书，上面写这成绩为70分，此时你也同样多了一个关联信息，就是一本英语四级考试证书；&lt;/p&gt;&lt;p&gt;这里我想表达的主要观点是：现实生活中的对象：1）兼具各种场景下的所有状态和行为特征；2）固有状态会时不时的变化，通过参与交互场景还会增加一些关联信息；3）行为会不断增多，一般是通过学习得到；因此，我们从中可以知道，现实生活中的对象肯定不是我们设计软件时候的对象，因为它是如此的复杂，包含了或关联了非常多的状态特征和行为特征；&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;2. 面向对象分析阶段时的对象：&lt;/p&gt;&lt;p&gt;既然是分析阶段，那我们就不要过多的考虑任何设计阶段的思想。我觉得在分析阶段，我们在分析对象时主要考虑两个方面：1）对象的状态特征变化规律；2）对象的行为特征变化规律；分析阶段，我们往往从某个场景出发，分析该场景中有哪些&amp;#8220;对象&amp;#8221;，此时的&amp;#8220;对象&amp;#8221;之所以加双引号是因为它不是真正的对象，而是真正的对象的某个方面，我们在某个场景下只关心对象的某个方面；我觉得分析阶段的对象和现实生活中的对象应该是一致的，或者至少是逻辑上是一致的。也就是说，在面向对象的分析阶段，我们应该将现实生活中我们所理解的对象的一切特征在脑子里描述清楚。比如同一个人，它在不同的场景下（一个场景代表了一个考虑问题的边界）会参与不同的交互活动。 这句话体现的含义是：1）同一个对象会参与不同的场景，行驶各种交互行为；2）同一个对象我们会根据我们不同的认识角度，对同一个对象的关注角度的不同，将其理解为不同的类型或角色；比如一个人，在家里可能是父亲，在公司可能是职员，在比赛场上可能是运动员。但无论我们给这个人授予什么样的称谓，这个人始终是同一个对象。所以，在面向对象的分析阶段，对象给我们的感觉是它在不停的变换其类型或角色；上面在谈到什么是真正的现实生活中的对象时提到，对象在参与到交互活动后会多出一些关联信息，这些信息是属于谁的呢？答案是：这些信息属于扮演了某个角色的对象的；之所以强调扮演了某个角色，是因为想让大家明确对象一定是在扮演某个角色参与到某个场景交互活动后才具有那些关联信息的。总结：我觉得在面向对象的分析阶段，我们分析的要点是：1）站在现实生活中真正的对象的角度去理解对象的状态特征和行为特征的变化规律；2）理解真正的对象和对象的某一个方面（即我们所关心的&amp;#8220;对象&amp;#8221;），3）理解同一个对象会扮演不同角色参与到不同交互场景；4）理解对象的关联信息如何产生，关联信息是属于谁的；&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div&gt;3. 面向对象设计阶段时的对象：&amp;nbsp;&lt;/div&gt;&lt;p&gt;首先说一下，目前的编程语言实现对象时，是以哪些方式让创建对象的。1）C#等基于类型的静态语言，类型规定了对象可以具有的状态特征和行为特征，对象的一切状态和行为都是由其所属的类型确定的；这又一个很明显的好处时，我们在任何时候都知道对象的类型或接口，从而就能明确知道其数据结构，也就知道对象的状态，从而可以方便的持久化对象的状态或者重建对象；但这种为对象带来状态和行为特征的设计思路同时也有一个缺点就是对象的类型或其表现出来的接口无法更改。这点是违背&amp;#8220;真正的对象&amp;#8221;或者&amp;#8220;分析阶段的对象&amp;#8221;的特征的；2）javascript等弱类型的动态语言，这种语言认为对象无类型，对象的状态和行为不需要从类型为模板获取，状态和行为可以随时附加到某个对象上。这种思路其实很好，因为很符合上面提到的真正的对象的状态特征与行为特征的变化规律。但是这种语言也有一些致命的缺点：1）由于没有类型，导致无法在使用时明确知道其具有哪些状态和行为，这会增加编程出错的可能性，只有在运行阶段在会检测到访问了不存在的状态或行为；2）同样是弱类型的原因，对象无法被持久化，因为不知道要持久化哪些状态，同样，更不用说重建对象了；所以，基于这两个缺点，我觉得动态语言不适合在服务器端大量使用去做工程实现业务逻辑，而在一些不需要持久化对象状态的客户端环境，只在内存中处理逻辑的情况下使用这种语言比较适合；&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;当我们在设计软件时，如果是用C#等静态语言、基于类和接口的语言去设计对象时，该如何设计呢？在设计阶段，我觉得目标就是把分析阶段得到的对象用尽量平滑的方式转换为设计；需要把握的要点是：1）从一个基本的类创建出对象；2）用尽量平滑的设计思路去支持一个对象表现出不同类型或角色的特点；举个例子吧：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #000000;"&gt;var&amp;nbsp;xuehua&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Person();&lt;br /&gt;xuehua.Eat();&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;吃饭&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;var&amp;nbsp;teacher&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;xuehua.ActAs&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ITeacher&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;扮演教师角色&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;teacher.Teach();&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;教书&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;xuehua这个对象首先是一个人，所以从Person这个基本类型中获取基本的状态特征和行为特征（如吃饭）；然后当xuehua去教书时，他会扮演教师的角色，扮演之后他就是一个教师了，然后他就具有了教师这个角色所赋予的行为（教书）了。上面的代码看上去和真正的对象在现实生活中的变化规律类似，非常平滑；这样做有几个好处：1）强类型；2）对象交互模型与现实生活中的交互模型完全一致，所以代码非常容易懂，可读性强；3）对象不会随着参与交互场景的增多而变得臃肿和复杂，因为由于引入了角色的概念，我们将交互模型实现为对象扮演某个角色参与交互活动的方式来设计，做到了对象动态被赋予身份，从而具有与该身份相关的状态特征和行为特征；4）对象参与交互场景后所关联的一些关联信息不会直接存放在对象上，而是放在了&amp;#8220;扮演了某个角色的对象&amp;#8221;上，在上面的例子中就是teacher对象；&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div&gt;4. 面向对象实现阶段时的对象：&lt;/div&gt;&lt;p&gt;那么如何实现这样的设计呢？&lt;/p&gt;&lt;p&gt;&lt;span style="line-height: 19px; font-family: &amp;quot;Courier New&amp;quot;; font-size: 13px; background-color: #f5f5f5;" &gt;&lt;span style="color: #000000;"&gt;var&amp;nbsp;teacher&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;xuehua.ActAs&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ITeacher&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;其实很简单，可以类用装饰模式来实现，我们都知道，设计模式中的装饰模式可以动态给一个对象增加状态或行为。所以在实现阶段，我们可以设计一个Teacher类，大概设计如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&lt;div&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Teacher&amp;nbsp;:&amp;nbsp;ITeacher&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Person&amp;nbsp;actor;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Teacher(Person&amp;nbsp;actor)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;.actor&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;actor;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;Teach()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;do&amp;nbsp;the&amp;nbsp;teach&amp;nbsp;operation.&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;}&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;font  size="2" face="'Courier New'"&gt;&lt;span style="line-height: 19px;" &gt;teacher就是实现阶段的对象，而Teacher类则是实现阶段的对象的类型；可以看到Teacher类关联了一个Person对象，同时实现了ITeacher角色接口。所以ActAs，&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="line-height: 19px; font-family: &amp;quot;Courier New&amp;quot;; font-size: 13px; background-color: #f5f5f5;" &gt;&lt;span style="color: #000000;"&gt;var&amp;nbsp;teacher&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;xuehua.ActAs&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ITeacher&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;这个函数做的事情就是在内部创建一个Teacher类的实例，该实例对当前的Person对象有一个引用，然后返回。也许你会说，返回回来的teacher对象已经不是原来的xuehua对象了，而是一个新的对象，并且封装了xuehua这个对象；没错，所以说这是实现上的问题。我们在关注业务时，关心的不是当前对象的真正类型，而是关心对象的状态特征、行为特征，或者技术化一点来讲就是关心对象的交互模型，关心的是对象扮演什么角色在进行交互。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;好了，就说这么多吧，下午要去参加知识分享。希望我的文章能带给大家一些启发。&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/netfocus/aggbug/2173099.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/netfocus/archive/2011/09/10/2173099.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
