<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/temp01.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.feedsky.com/T2sNotebook" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/T2sNotebook" type="application/rss+xml"></fs:self_link><lastBuildDate>Thu, 28 Jan 2010 13:48:00 GMT</lastBuildDate><title>博客园-T2's Notebook</title><description>.NET,Ajax,System Arthitecture and Design Pattern</description><link>http://www.cnblogs.com/leoo2sk/</link><language>zh-cn</language><pubDate>Tue, 09 Feb 2010 15:10:37 GMT</pubDate><item><title>.NET平台上的Model-View-Presenter模式实践</title><link>http://www.cnblogs.com/leoo2sk/archive/2010/01/28/mvp-in-practice-based-on-dot-net.html</link><description>&lt;p&gt;阅读: 1488 评论: 32 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2010-01-28 21:48 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2010/01/28/mvp-in-practice-based-on-dot-net.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;为什么要写这篇文章&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 笔者当前正在负责研究所中一个项目，这个项目基于.NET平台，初步拟采用C/S部署体系，所以选择了Windows Forms作为其UI。经过几此迭代，我们发现了一个问题：虽然业务逻辑已经封装到Services层中，但诸多的UI逻辑仍然弥漫在各个事件Listener中，使得UI显得臃肿不堪，并且存在诸多重复性代码。另外，需求提供方说，根据实际需要，不排除将部署结构改为B/S的可能性，甚至可能会要求此系统同时支持C/S和B/S两种部署方式。那么，如果保持目前将UI逻辑编码到Windows Forms中的方式，到时这些UI逻辑将无法复用，修改部署方式的代价很大。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 为了解决以上两个问题，笔者和相关人员商量后，决定引入既有成熟模式，重新设计表示层的架构方式，并重构既有代码。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 提到表示层（Presentation Layer）的模式，我想大家脑海中第一个闪过的很可能是经典的MVC（Model-View-Controller）。我最初也准备使用MVC，但经过分析和实验后，我发现MVC并不适合目前的情况，因为MVC的结构相对复杂，Model和View之间要实现一个Observer模式，并实现双向通信。这样重构起来Services层也必须修改。我并不想修改Services层，而且我想将View和Model彻底隔离，因为我个人并不喜欢View和Model直接通信的架构方式。最终，我选择了MVP（Model-View-Presenter）模式。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 经过两天的重构和验证，目前已经将MVP正式引入项目的表示层，并且解决了上文提到的两个问题。在这期间，积累了少许关于在.NET平台上实践MVP的经验，在这里汇集成此文，和朋友们共享。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UI与P Logic&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 首先，我想先明确一下UI和P Logic的概念。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff6600;&quot;&gt;表示层可以拆分为两个部分：User Interface（简称UI）和Presentation Logic（简称P Logic）。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff6600;&quot;&gt;UI是系统与用户交互的界面性概念，它的职责有两个&amp;mdash;&amp;mdash;接受用户的输入和向用户展示输出。&lt;/span&gt;UI应该是一个纯静态的概念，本身不应包含任何逻辑，而单纯是一个接受输入和展示输出的&amp;ldquo;外壳&amp;rdquo;。例如，一个不包含逻辑的Windows Form，一张不包含逻辑的页面，一个不包含逻辑的Flex界面，都属于UI。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff6600;&quot;&gt;P Logic是表示层应有的逻辑性内容。&lt;/span&gt;例如，某个文本内容不能为空，当某个事件发生时获取界面上哪些内容，这都属于P Logic。应该指出，&lt;span style=&quot;color: #ff6600;&quot;&gt;P Logic应该是抽象于具体UI的，它的本质是逻辑，可以复用到任何与此逻辑相符的UI。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; UI与P Logic之间的联系是事件，UI可以根据用户的动作触发各种事件，P Logic响应事件并执行相应的逻辑。P Logic对UI存在约束作用，P Logic规定一套UI契约，UI要根据契约实现，才能被相应的P Logic调用。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下图展示了UI与P Logic的结构及交互原理。&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010012820054895.png&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;图1、UI与P Logic&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Model-View-Presenter模式&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MVP模式最早由Taligent的Mike Potel在《MVP: Model-View-Presenter The Taligent Programming Model for C++ and Java》（&lt;a href=&quot;http://www.wildcrest.com/Potel/Portfolio/mvp.pdf&quot;&gt;点击这里下载&lt;/a&gt;）一文中提出。MVP的提出主要是为了解决MVC模式中结构过于复杂和模型-视图耦合性过高的问题。&lt;span style=&quot;color: #ff6600;&quot;&gt;MVP的核心思想是将UI分离成View，将P Logic分离成Presenter，而业务逻辑和领域相关逻辑都分离到Model中。View和Model完全解除耦合，不再像MVC中实现一个Observer模式，两者的通信则依靠Presenter进行。&lt;/span&gt;Presenter响应View接获的用户动作，并调用Model中的业务逻辑，最后将用户需要的信息返回给View。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下图直观表示了MVP模式：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010012820045716.png&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;图2、MVP模式&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 图2清楚地展示了MVP模式的几个特点：&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1、View和Model完全解耦，两者不发生直接关联，通过Presenter进行通信。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、Presenter并不是与具体的View耦合，而是和一个抽象的View Interface耦合，View Interface相当于一个契约，抽象出了对应View应实现的方法。只要实现了这个接口，任何View都可以与指定Presenter兼容，从而实现了P Logic的复用性和视图的无缝替换。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3、View在MVP里应该是一个&amp;ldquo;极瘦&amp;rdquo;的概念，最多也只能包含维护自身状态的逻辑，而其它逻辑都应实现在Presenter中。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 总的来说，使用MVP模式可以得到以下两个收益：&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff6600;&quot;&gt;1、将UI和P Logic两个关注点分离，得到更干净和单一的代码结构。&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #ff6600;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、实现了P Logic的复用以及View的无缝替换。&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;在.NET平台上实现MVP模式&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这一节通过一个示例程序展示在.NET平台上实现MVP的一种实践方法。本来想通过我目前负责的实际项目中的代码片段作为Demo，但这样做存在两个问题：一是这样做可能会违反学校的保密守则，二是这个项目应用了许多其他框架和模式，如通过Unity实现依赖注入，通过PostSharp实现AOP来负责异常处理和事务管理等，通过NHibernate实现的ORM等等，这样如果读者不了解系统整体架构就很难完全读懂代码片段，MVP模式不够突出。因此，我专门为这篇文章实现了一个Demo，其中的MVP实践方式与实际项目中是一致的，而且Demo规模小，排除了其他干扰，使得读者更容易理解其中的MVP实现方式。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个简单的Demo运行效果如下：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010012820252432.png&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;图3、Demo界面&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个Demo的功能如下：这是一个简单的点餐软件。系统中存有餐厅所有菜品的信息，客户只需在界面右侧输入菜品名称和数量，单击&amp;ldquo;添加&amp;rdquo;按钮，菜品就会被添加到左侧点餐列表，并显示此菜品详细信息。如果所点菜品不存在则软件会给出提示。另外，在左侧已点餐品列表中右键单击某个条目，在弹出菜单中点击&amp;ldquo;删除&amp;rdquo;，则可将此菜品从列表删除。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面分步骤介绍应用了MVP模式的实现方式。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;第一步，解决方法及工程结构&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个Demo共有三个工程，MVPSimple.Model为Mock方式实现的Services，作为Model；MVPSimple.Presenters为Presenter工程，其中包括Presenter和View Interface；MVPSimple.WinUI为View的Windows Forms实现。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;第二步，构建Mock方式的Services&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 因为重点在于表示层，所以这里的Services使用了Mock方式，并没有包含真正的业务领域逻辑。其中MVPSimple.Model工程里两个文件的代码如下：&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #3366ff;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #3366ff;&quot;&gt;FoodDto.cs:&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brush:csharp;collapse:true;&quot;&gt;using System;

namespace MVPSimple.Model
{
    /// &amp;lt;summary&amp;gt;
    /// 表示菜品类别的枚举类型
    /// &amp;lt;/summary&amp;gt;
    public enum FoodType
    {
        主菜 = 1,
        汤 = 2,
        甜品 = 3,
    }

    /// &amp;lt;summary&amp;gt;
    /// 菜品的Data Transfer Object
    /// &amp;lt;/summary&amp;gt;
    public class FoodDto
    {
        /// &amp;lt;summary&amp;gt;
        /// ID，标识字段
        /// &amp;lt;/summary&amp;gt;
        public Int32 ID { get; set; }

        /// &amp;lt;summary&amp;gt;
        /// 菜品名称
        /// &amp;lt;/summary&amp;gt;
        public String Name { get; set; }
        
        /// &amp;lt;summary&amp;gt;
        /// 菜品类型
        /// &amp;lt;/summary&amp;gt;
        public FoodType Type { get; set; }

        /// &amp;lt;summary&amp;gt;
        /// 菜品价格
        /// &amp;lt;/summary&amp;gt;
        public Double Price { get; set; }

        /// &amp;lt;summary&amp;gt;
        /// 点菜数量
        /// &amp;lt;/summary&amp;gt;
        public Int32 Amount { get; set; }
    }
}
&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #3366ff;&quot;&gt;&lt;strong&gt;FoodServices.cs:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brush:csharp;collapse:true;&quot;&gt;using System;
using System.Collections.Generic;

namespace MVPSimple.Model
{
    /// &amp;lt;summary&amp;gt;
    /// 菜品Services的Mock实现
    /// &amp;lt;/summary&amp;gt;
    public class FoodServices
    {
        private IList&amp;lt;FoodDto&amp;gt; foodList = new List&amp;lt;FoodDto&amp;gt;();

        /// &amp;lt;summary&amp;gt;
        /// 默认构造函数，初始化各个菜品
        /// &amp;lt;/summary&amp;gt;
        public FoodServices()
        {
            this.foodList.Add(
                new FoodDto()
                {
                    ID = 1,
                    Name = &quot;牛排&quot;,
                    Price = 60.00,
                    Type = FoodType.主菜,
                }
            );

            this.foodList.Add(
                new FoodDto()
                {
                    ID = 2,
                    Name = &quot;法式蜗牛&quot;,
                    Price = 120.00,
                    Type = FoodType.主菜,
                }
            );

            this.foodList.Add(
                new FoodDto()
                {
                    ID = 3,
                    Name = &quot;水果沙拉&quot;,
                    Price = 58.00,
                    Type = FoodType.甜品,
                }
            );

            this.foodList.Add(
                new FoodDto()
                {
                    ID = 4,
                    Name = &quot;奶油红菜汤&quot;,
                    Price = 15.00,
                    Type = FoodType.汤,
                }
            );

            this.foodList.Add(
                new FoodDto()
                {
                    ID = 5,
                    Name = &quot;杂拌汤&quot;,
                    Price = 20.00,
                    Type = FoodType.汤,
                }
            );
        }

        /// &amp;lt;summary&amp;gt;
        /// 按照菜品名称获取菜品详细信息
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;foodName&quot;&amp;gt;菜品名称&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;含有指定菜品信息的DTO&amp;lt;/returns&amp;gt;
        public FoodDto GetFoodDetailByName(String foodName)
        {
            foreach (FoodDto f in this.foodList)
            {
                if (f.Name.Equals(foodName))
                {
                    return f;
                }
            }

            return new FoodDto() { ID = 0 };
        }
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;第三步，通过View Interface规定View契约&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果想实现Presenter和View的交互和无缝替换，必须在它们之间规定一个契约。一般来说，每一张界面（注意是界面不是视图）都应该对应一个View接口，不过由于Demo只有一个页面，所以也只有一个View接口。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里需要特别强调，View接口必须抽象于任何具体视图而服务于Presenter，所以，View接口中绝不能出现任何与具体视图相关的元素。例如，我们的Demo中是使用Windows Forms作为视图实现，但View接口中绝不可出现与Windows Forms相耦合的元素，如返回一个Winform的TextBox。因为如果这样做的话，使用其他技术实现的View就无法实现这个接口了，如使用Web Forms实现，而Web Forms是不可能返回一个Winform的TextBox的。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面给出视图接口的代码。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #3366ff;&quot;&gt;&lt;strong&gt;IMainView.cs:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brush:csharp;collapse:true;&quot;&gt;using System;
using System.Collections.Generic;
using MVPSimple.Model;

namespace MVPSimple.Presenters
{
    /// &amp;lt;summary&amp;gt;
    /// MainView的接口，所有MainView必须实现此接口，此接口暴露给Presenter
    /// &amp;lt;/summary&amp;gt;
    public interface IMainView
    {
        /// &amp;lt;summary&amp;gt;
        /// View上的菜品名称
        /// &amp;lt;/summary&amp;gt;
        String foodName { get; set; }

        /// &amp;lt;summary&amp;gt;
        /// View上点菜数量
        /// &amp;lt;/summary&amp;gt;
        Int32 Amount { get; set; }

        /// &amp;lt;summary&amp;gt;
        /// 判断某一菜品是否已经存在于点菜列表中
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;foodName&quot;&amp;gt;菜品名称&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;结果&amp;lt;/returns&amp;gt;
        bool IsExistInList(String foodName);

        /// &amp;lt;summary&amp;gt;
        /// 将某一菜品加入点菜列表
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;food&quot;&amp;gt;菜品DTO&amp;lt;/param&amp;gt;
        void AddFoodToList(FoodDto food);
        
        /// &amp;lt;summary&amp;gt;
        /// 将某一已点菜品从列表中移除
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;foodName&quot;&amp;gt;欲移除的菜品名称&amp;lt;/param&amp;gt;
        void RemoveFoodFromList(String foodName);

        /// &amp;lt;summary&amp;gt;
        /// View显示提示信息给用户
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;message&quot;&amp;gt;信息内容&amp;lt;/param&amp;gt;
        void ShowMessage(String message);

        /// &amp;lt;summary&amp;gt;
        /// View显示确认信息并返回结果
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;message&quot;&amp;gt;信息内容&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;用户回答是确定还是取消。True - 确定，False - 取消&amp;lt;/returns&amp;gt;
        bool ShowConfirm(String message);
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以看到，IMainView抽象了如图3所示的界面，但又不包含任何与Windows Forms相耦合的元素，因此如果需要，以后完全可以使用Web Forms、WPF或SL等技术实现这个接口。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;第四步，实现Presenter&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上文说过，一个界面应该对应一个Presenter，这个Demo里只有一个界面，所以只有一个Presenter。Presenter仅于视图接口耦合，而并不和具体视图耦合，最好证据就是Presenter工程根本没有引用WinUI工程！代码如下:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #3366ff;&quot;&gt;&lt;strong&gt;MainPresenter.cs:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brush:csharp;collapse:true;&quot;&gt;using System;
using System.Collections.Generic;
using MVPSimple.Model;

namespace MVPSimple.Presenters
{
    /// &amp;lt;summary&amp;gt;
    /// MainView的Presenter
    /// &amp;lt;/summary&amp;gt;
    public class MainPresenter
    {
        /// &amp;lt;summary&amp;gt;
        /// 当前关联View
        /// &amp;lt;/summary&amp;gt;
        public IMainView View { get; set; }

        /// &amp;lt;summary&amp;gt;
        /// 默认构造函数，初始化View
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;view&quot;&amp;gt;MainView对象&amp;lt;/param&amp;gt;
        public MainPresenter(IMainView view)
        {
            View = view;
        }

        #region Acitons

        /// &amp;lt;summary&amp;gt;
        /// Action:将所点菜品增加到点菜列表
        /// &amp;lt;/summary&amp;gt;
        public void AddFoodAction()
        {
            if (String.IsNullOrEmpty(View.foodName))
            {
                View.ShowMessage(&quot;请选输入菜品名称&quot;);
                return;
            }
            if (View.Amount &amp;lt;= 0)
            {
                View.ShowMessage(&quot;点菜的份数至少要是一份&quot;);
                return;
            }
            if (View.IsExistInList(View.foodName))
            {
                View.ShowMessage(String.Format(&quot;菜品【{0}】已经在您的菜单中&quot;, View.foodName));
                return;
            }

            FoodServices foodServ = new FoodServices();
            FoodDto food = foodServ.GetFoodDetailByName(View.foodName);
            if (food.ID == 0)
            {
                View.ShowMessage(String.Format(&quot;抱歉，本餐厅没有菜品【{0}】&quot;,View.foodName));
                return;
            }

            View.AddFoodToList(food);
        }

        /// &amp;lt;summary&amp;gt;
        /// Action:从点菜列表移除某一菜品
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;foodName&quot;&amp;gt;被移除菜品的名称&amp;lt;/param&amp;gt;
        public void RemoveFoodAction(String foodName)
        {
            if (View.ShowConfirm(&quot;确定要删除吗？&quot;))
            {
                View.RemoveFoodFromList(foodName);
            }
        }

        #endregion
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;第五步，实现View&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里我们使用Windows Forms实现View。如果朋友们有兴趣，完全可以自己试着用Web或WPF实现以下视图，同时可以验证P Logic的可复用性和视图无缝替换，亲身体验一下MVP模式的威力。Winform的View代码如下。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #3366ff;&quot;&gt;&lt;strong&gt;frmMain.cs:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brush:csharp;collapse:true;&quot;&gt;using System;
using System.Windows.Forms;
using MVPSimple.Model;
using MVPSimple.Presenters;

namespace MVPSimple.WinUI
{
    /// &amp;lt;summary&amp;gt;
    /// MainView的Windows Forms实现
    /// &amp;lt;/summary&amp;gt;
    public partial class frmMain : Form, IMainView
    {
        /// &amp;lt;summary&amp;gt;
        /// 相关联的Presenter
        /// &amp;lt;/summary&amp;gt;
        private MainPresenter presenter;

        /// &amp;lt;summary&amp;gt;
        /// 默认构造函数，初始化Presenter
        /// &amp;lt;/summary&amp;gt;
        public frmMain()
        {
            InitializeComponent();
            this.presenter = new MainPresenter(this);
        }

        #region IMainView Members

        /// &amp;lt;summary&amp;gt;
        /// View上的菜品名称
        /// &amp;lt;/summary&amp;gt;
        public String foodName
        {
            get { return this.tbFoodName.Text; }
            set { this.tbFoodName.Text = value; }
        }

        /// &amp;lt;summary&amp;gt;
        /// View上点菜数量
        /// &amp;lt;/summary&amp;gt;
        public Int32 Amount
        {
            get { return (Int32)this.tbAmount.Value; }
            set { this.tbAmount.Value = (Decimal)value; }
        }

        /// &amp;lt;summary&amp;gt;
        /// 判断某一菜品是否已经存在于点菜列表中
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;foodName&quot;&amp;gt;菜品名称&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;结果&amp;lt;/returns&amp;gt;
        public bool IsExistInList(String foodName)
        {
            foreach (ListViewItem i in this.lvFoods.Items)
            {
                if (i.Text == foodName)
                {
                    return true;
                }
            }

            return false;
        }

        /// &amp;lt;summary&amp;gt;
        /// 将某一菜品加入点菜列表
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;food&quot;&amp;gt;菜品DTO&amp;lt;/param&amp;gt;
        public void AddFoodToList(FoodDto food)
        {
            ListViewItem item = new ListViewItem();
            Double price = food.Price * (Double)this.tbAmount.Value;

            item.Text = food.Name;
            item.SubItems.Add(food.Type.ToString());
            item.SubItems.Add(this.tbAmount.Value.ToString());
            item.SubItems.Add(price.ToString());
            this.lvFoods.Items.Add(item);
        }

        /// &amp;lt;summary&amp;gt;
        /// 将某一已点菜品从列表中移除
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;foodName&quot;&amp;gt;欲移除的菜品名称&amp;lt;/param&amp;gt;
        public void RemoveFoodFromList(String foodName)
        {
            foreach (ListViewItem i in this.lvFoods.Items)
            {
                if (i.Text == foodName)
                {
                    this.lvFoods.Items.Remove(i);
                }
            }
        }

        /// &amp;lt;summary&amp;gt;
        /// View显示提示信息给用户
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;message&quot;&amp;gt;信息内容&amp;lt;/param&amp;gt;
        public void ShowMessage(String message)
        {
            MessageBox.Show(message, &quot;信息&quot;, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        /// &amp;lt;summary&amp;gt;
        /// View显示确认信息并返回结果
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&quot;message&quot;&amp;gt;信息内容&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;用户回答是确定还是取消。True - 确定，False - 取消&amp;lt;/returns&amp;gt;
        public bool ShowConfirm(String message)
        {
            DialogResult result = MessageBox.Show(message, &quot;确认&quot;, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
            return DialogResult.OK == result;
        }

        #endregion

        #region Event Listeners

        private void btnAdd_Click(object sender, EventArgs e)
        {
            this.presenter.AddFoodAction();
        }

        private void miDeleteFood_Click(object sender, EventArgs e)
        {
            if (this.lvFoods.SelectedItems.Count != 0)
            {
                String foodName = this.lvFoods.SelectedItems[0].Text;
                this.presenter.RemoveFoodAction(foodName);
            }
        }

        #endregion
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以看到，使用了MVP后，View的代码变的非常干净整洁，以前充斥着厚重表示逻辑的事件Listener方法变得&amp;ldquo;瘦&amp;rdquo;了许多。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 完成以上几步后，就可以运行这个Demo看效果了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;完整Demo在此下载：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这篇文章首先讨论表示层的组成，说明User Interface和Presentation Logic是表示层的两个重要组成部分，并分别说明了两者的作用及交互方式。接着讨论了MVP模式。最后，通过一个Demo展示了在.NET平台上实现MVP的一种实践方式。应该说，MVP很类似简化了MVC，MVP不但可以分离关注、使得代码变得干净整洁、并实现P Logic的复用，而且实现起来比MVC在结构上要简单很多。MVP是一种模式，本身有诸多实现方式，本文只是介绍了笔者使用的一种实践，朋友们也可以在此基础上摸索自己的实践。&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;a rel=&quot;license&quot; target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot;&gt;&lt;img align=&quot;left&quot; src=&quot;http://i.creativecommons.org/l/by/2.5/cn/88x31.png&quot; alt=&quot;Creative Commons License&quot; style=&quot;border-width: 0px;&quot; /&gt;&lt;/a&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;本文基于&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot; title=&quot;Creative Commons Attribution 2.5 China Mainland License&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;署名 2.5 中国大陆&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;许可协议发布，欢迎转载，演绎或用于商业目的，但是必须保留本文的署名&lt;/span&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;张洋&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;（包含链接）。如您有任何疑问或者授权方面的协商，请&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://space.cnblogs.com/msg/send/leoo2sk&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;给我留言&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;。&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1657115.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 32　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2010/01/28/mvp-in-practice-based-on-dot-net.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2010/01/28/mvp-in-practice-based-on-dot-net.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330716769/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2010/01/28/mvp-in-practice-based-on-dot-net.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330716769/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330716769/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 28 Jan 2010 21:48:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2010/01/28/mvp-in-practice-based-on-dot-net.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2010/01/28/mvp-in-practice-based-on-dot-net.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330716769/5313554</fs:itemid></item><item><title>单元测试之道（使用NUnit）</title><link>http://www.cnblogs.com/leoo2sk/archive/2010/01/13/pragmatic-unit-testing-with-nunit.html</link><description>&lt;p&gt;阅读: 1927 评论: 28 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2010-01-13 00:02 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2010/01/13/pragmatic-unit-testing-with-nunit.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;首先来看下面几个场景你是否熟悉&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #003366;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1、你正在开发一个系统，你不断地编码-编译-调试-编码-编译-调试&amp;hellip;&amp;hellip;终于，你负责的功能模块从上到下全部完成且编译通过！你长出一口气，怀着激动而又忐忑的心情点击界面上的按钮，顿时你刚刚的轻松感烟消云散：系统无法正常工作，你想读的数据显示不出来，你想存的东西也送不到数据库&amp;hellip;&amp;hellip;于是，你再次回到IDE里，设断点、调试、一层一层跟踪，当你精疲力尽终于将数据送到数据库里，你又发现了其它问题，于是你继续设断点、调试、编译、调试&amp;hellip;&amp;hellip;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #003366;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、你狂躁地敲击着键盘和鼠标，咒骂着不断出现的bug：啊？这里怎么没返回值啊！哎？这里不该是0啊！不对啊，这里怎么没数据&amp;hellip;&amp;hellip;你永远不知道还有多少bug，你也永远不知道你的改动会不会引入其它bug&amp;mdash;&amp;mdash;这里有几十个甚至上百个类，几百几千个方法！我不能都照顾到啊！你感觉bugs像敲击鼹鼠游戏中的鼹鼠：打下了这个，另一个又从其它洞口露出头来&amp;hellip;&amp;hellip;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #003366;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3、也许是毕业答辩的演示，也许是客户的审查，你小心地打开自己要演示的系统，进行着预定的操作，忽然，有个功能不能正常运行，你大汗淋漓，在答辩老师或者客户质疑且不满的目光下你试了又试，但还是于事无补&amp;hellip;&amp;hellip;于是，答辩老师可能扭头便走，客户可能愤然离去，然后离去的还有你的学位证和项目奖金。当后来你检查代码时，发现这一切竟然只是因为一个底层工具类中一个方法输出结果为空。&lt;/span&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #008080;&quot;&gt;单元测试（Unit Test）的一个测试用例（Test Case）是一小段代码，这段代码用于测试一个小的程序功能（一般是一个方法或相关的几个方法）行为是否正常。&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;下面给出一个实际项目中单元测试用例的代码，大家可以不用深究这段代码中的细节，这里贴这段代码只是给大家一个直观的感觉。&lt;/p&gt;
&lt;div class=&quot;cnblogs_code&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 1&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 2&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 测试基本的添加及删除角色是否正确&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 3&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 4&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;[Test]&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 5&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; TestAddAndRemoveRole()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 6&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 7&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    IRoleServices roleServ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityHelper.CreateContainer().Resolve&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IRoleServices&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 8&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    IRoleRepository roleRep &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityHelper.CreateContainer().Resolve&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IRoleRepository&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 9&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    Assert.IsNotNull(roleServ);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;10&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    Assert.IsNotNull(roleRep);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;11&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;12&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    String timeStamp &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; DateTime.Now.ToString();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;13&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    RoleDto newRole &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; RoleDto()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;14&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;15&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        Name &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;测试角色&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; timeStamp,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;16&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        Desciption &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;此角色仅供测试使用&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;17&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    };&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;18&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    roleServ.AddRole(newRole);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;19&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;20&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    RoleDto addedRole &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; roleRep.GetRoleByName(&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;测试角色&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; timeStamp);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;21&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    Assert.AreNotEqual(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #800080;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, addedRole.ID);&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;确认新角色添加成功&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;22&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;23&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    roleServ.RemoveRole(addedRole.ID);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;24&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    Assert.AreEqual(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #800080;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, roleRep.GetRoleByName(&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;测试角色&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; timeStamp).ID);&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;确认刚才添加的角色删除成功&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;25&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;上面的Unit Test Case来自我目前负责的一个项目，这段代码的作用是测试Services层对角色的添加和删除是否正常工作。这里大家可以先不必太细究代码，后面会有详解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么大家不使用单元测试&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 按照惯例，说完什么是单元测试，就该说为什么要使用单元测试了。但是，我在这里想先和大家讨论，为什么很多开发人员知道单元测试，也&amp;ldquo;认为&amp;rdquo;单元测试有必要，但绝大多数开发人员都不写单元测试，能认真对待单元测试的开发人员更是寥寥无几了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我私下调查了一些开发人员，发现大家不写单元测试主要有两点原因：一是对单元测试存在很多误解，二是没有真正意识到单元测试的收益。下面我就这两点做一些讨论。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 首先，我们来看看大家对单元测试普遍存在哪些误解。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;误解1：单元测试属于测试工作，应该由测试人员来完成，所以单元测试不属于开发人员的职责范围。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008000;&quot;&gt;正解1：单元测试虽然叫做&amp;ldquo;测试&amp;rdquo;，但实际属于开发范畴，应该由开发人员来做。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在大多数开发人员眼里，&amp;ldquo;开发&amp;rdquo;和&amp;ldquo;测试&amp;rdquo;是两个泾渭分明的范畴，他们认为：开发人员的工作就是写新代码，实现新功能，至于代码的测试，那是测试人员的职责，我只要让代码编译通过就行了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我们都知道，软件是很复杂很抽象的东西，软件开发人员压力都很大，况且人非圣贤，强求开发人员开发出没有缺陷的程序是不现实的，所以才有了&amp;ldquo;测试工程师&amp;rdquo;这一职位。但是，&lt;span style=&quot;color: #008080;&quot;&gt;&lt;strong&gt;开发人员至少应该保证一点：你写的每一个函数或方法（Function）应该能够正常完成功能，即行为正常。&lt;/strong&gt;&lt;/span&gt;软件最终可能会有缺陷，这不是开发人员完全可以控制的，但你写了一个类，类里有4个方法，作为开发人员应该保证这四个方法实现了&amp;ldquo;眼下&amp;rdquo;的功能。例如，你写了一个获取IoC容器的工具类，你总要保证其中的GetContainer方法能正确返回一个Container吧。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 所以，单元测试虽然叫&amp;ldquo;测试&amp;rdquo;，但实际其属于开发范畴，其目的是保证开发的功能子项能完成正确实现其基本功能。&lt;span style=&quot;color: #008080;&quot;&gt;&lt;strong&gt;甚至我个人认为，当开发人员开发每一个功能子项（通常是方法）时，如果不能附带一配套的单元测试代码，都不能算开发完成。换言之，单元测试代码应该是开发人员必须提供的要素。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;误解2：单元测试是一种测试，其功能是对代码进行检测。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008000;&quot;&gt;正解2：单元测试是一种工具，其功能除了是对代码进行检测，更重要的是对软件的质量起到一种保证，并且是为他人和后续编码、重构工作提供的一种十分美妙的工具！&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 单元测试不是一种测试。没错，我不是在说疯话，单元测试其实是一种工具。特别是当自动化测试软件（如NUnit、JUnit）出现后，单元测试更像是一种工具了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 当你处在一个多人开发团队中，你需要和其他队友配合开发，而这在程序层面则表现为你开发的Class会被别人用，而你也会用别人开发的Class。我们每个人都希望别人交给我的Class是行为正确的，如果我拿到一个同事写的数据库操作类DBHelper，但发现其中的Connect方法根本无法连接上数据库（虽然没有编译错误），那我将非常郁闷。所以，在交给别人一个Class之前，你应该使用Unit Test保证这个Class是正常实现功能的，在交付的时候，你应该一手递上刚出炉的Class，然后另一只手递上配套的Unit Test，然后说：嘿！哥们，这是你要的类，而这个是配套的单元测试，你可以随时使用自动化测试工具运行它以便迅速知道这个类是否工作正常。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这将会是个很棒的工具，你的队友以后可能会想知道它的改动是否影响了你提供的类的功能，也可能会对你的类进行重构，但无论何时，它只要拿出你的配套单元测试，让自动化测试工具跑一下，不出几秒，就知道你提供的类是否还正常完成功能。即使是对于你自己，以后也会有很多机会用到它。而当你写的代码出现bug，你可以拿出你这段代码调用的所有类的单元测试跑一遍，很快就能知道到底是你依赖的类出了问题还是你自己代码有问题，而不必抓狂似地到处设断点。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;误解3：项目经理或技术主管没有要求写单元测试，所以不用写。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008000;&quot;&gt;正解3：写单元测试应该成为开发人员的一种本能，开发本身就应该包含些单元测试。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 就像项目经理不用告诉你要使用计算机写程序一样，写单元测试应该成为开发人员的必须动作。因为你是开发人员，因为你在做开发，所以你必须写单元测试，就这么简单。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;误解4：写单元测试获益者是测试人员，而开发人员无法从中获益，还要搭上宝贵的时间。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008000;&quot;&gt;正解4：写单元测试谁都获得不了像开发人员获得的那么大的益处。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 有了单元测试，你可以随时从同事手中接过值得信赖的代码；有了单元测试，你可以随时保证你写的代码行为正确；有了单元测试，你可以随时通过自动化操作得知某个Class行为是否正确；有了单元测试，你以后的Debug和重构工作将变得轻松异常；有了单元测试，&amp;hellip;&amp;hellip;没有人比开发人员从中获得的利益更大了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么开发人员很难意识到单元测试的收益&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 关于这点，我认为有两个重要原因。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第一、绝大多数开发人员没有尝试过贯彻单元测试。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个很好理解，如果你不亲口尝尝一道菜，即使是海参鲍鱼，你也不知道它有多美味。我曾经也是其中的一员，但当我第一次将单元测试贯彻于项目中并尝到甜头后，我就爱上&amp;ldquo;她&amp;rdquo;了，所以，迈出一地步，很关键。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第二、人有一种天性：相比长远的更大利益，人们更倾向于眼前的小的多的利益，正所谓&amp;ldquo;贪小便宜吃大亏&amp;rdquo;是也。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 想起了美国人类行为专家的一个实验：他到了美国一个小学，里面一个一年级班级有48个孩子，他给每个孩子5颗做了特殊标记的糖，并告诉他们如果到一周后谁能一颗都不吃，我就给他100颗糖。一周后，48个孩子中只有4个孩子做到了。他跟踪了这48个孩子30年的成长，最后发现那4个孩子都成为了十分成功的人物，他们4个人30年后拥有的财富是剩下44个孩子财富总和的3倍。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 同样道理，即使很多开发人员也知道好的单元测试能让以后省不少心，但他们也宁可省掉写单元测试时间去堆砌代码。因为我们总觉得今天省掉1个小时多写一个类更有的赚，虽然我们以后要为省掉的1小时多付出3个小时去抓狂。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;小结一下&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上面写了很多，所以我认为这里有必要小结一下，整理一下思绪。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/strong&gt;单元测试的概念&amp;mdash;&amp;mdash;一小段代码，用于检查一个或几个相关的方法行为是否正确。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 单元测试的本质&amp;mdash;&amp;mdash;随功能代码一起提供的一个配套工具。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 单元测试的用途&amp;mdash;&amp;mdash;保证交付Class行为正确，随时可用于自动化检测其对应的Class行为是否正确，对整个软件的质量是一种保证，对缺陷是一种控制。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么需要单元测试&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我忽然发现，写了上面的文字后，再来讨论这个问题有些多余了，那么我尽量写简短一点。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008080;&quot;&gt;1、开发人员有&lt;strong&gt;义务&lt;/strong&gt;提供行为正确的Class，也有&lt;strong&gt;权利&lt;/strong&gt;得到行为正确的Class。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 很明显，如果你和你的同事，都能重视单元测试的话，你将同时履行这份义务和享受这份权利。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008080;&quot;&gt;2、尽早消灭缺陷。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 缺陷越早消灭所付出的代价越小，而越往后其代价呈指数增长，这是有充分的实验数据证明的，并已经被写到每一本软件工程教科书中。毫无疑问，当你交付一个Class前，就将其行为上的缺陷全部扼杀，那将取得巨大的收益。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008080;&quot;&gt;3、使合作变得愉快顺畅。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 想想看，每个你调用的Class，都是经过你的同事测试，确保行为是正确的，这是多么美妙的事情！我们写程序经常没有安全感，我们战战兢兢，很大程度上是因为我们没信心认为调用的每个Class行为是正确的。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008080;&quot;&gt;4、得到一个有力的工具，会在后续工作中大显身手的工具。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果每个Class都有配套的单元测试，好的，如果你想确认你的改动有没有影响到其它几个Class，run it!如果你想看看你调用的类是否行为正确，run it!如果你在重构，想看看重构有没有改变或损害其行为，run it!你正在调试一个bug但很难定位问题出在哪个地方，run it!你想看看目前项目中所有集成进来的代码是否行为都正确 run it! &amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;.NET平台下使用NUnit进行单元测试的实例&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果你愿意，你可以手工设计和运行单元测试，但这是低效和让人恐惧的。目前，各个平台上都有较为流行的自动化单元测试工具，像Visual Studio 2008本身就集成了单元测试功能。但是，我更愿和大家分享的是一个叫NUnit的工具。其官方网站为：&lt;a href=&quot;http://www.nunit.org/&quot;&gt;http://www.nunit.org/&lt;/a&gt;。这是一个开源且免费的.NET平台下自动化单元测试工具，可以在其官网下载。NUnit是XUnit家族的一员，其体积小巧，使用简单，但功能强大，一直是我做单元测试的首选。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 另外，这个例子我选取目前我正负责的一个实际项目，这是一个国家863项目。这个项目使用了敏捷开发方法，贯彻了以保证为目的的测试驱动、持续集成等实践。我将截取其中几个片段和大家分享一下单元测试的一些实践。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 值得一提的是，我对这个项目的单元测试要求是相对严格的，我们使用的配置管理工具是SVN，作为项目负责人，我对所有开发人员有一个要求：&lt;span style=&quot;color: #008080;&quot;&gt;&lt;strong&gt;每一个新开发的Class，必须有配套的单元测试，并且在每次Commit到SVN前，不仅仅要保证Commit的代码编译没问题，还要跑通所有单元测试，否则不准Commit到SVN。&lt;/strong&gt;&lt;/span&gt;这就保证了每个人Update到的Class都是行为正确的。再配合面向接口编程方法和Mock技术，大大提高了代码的可测试性，使得开发过程一直比较让人满意。刚开始大家觉得我的要求有些过分，但是当每次结合时几乎都没有出现问题，每次刚刚集成的新功能都能顺利在UI上跑通，大家也就慢慢接受了，并且渐渐都对待单元测试非常认真。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个项目的整体结构大家可以先看一下，其中XUnit项目就是单元测试项目。&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010011223082898.gif&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;图1、解决方案结构图&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 其中的单元测试Case进行了一定的组织，相应工程的Case放在了不同目录下。当然，这个大家可以根据具体情况自行确定组织方式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对UnityHelper的单元测试&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个项目选用的依赖注入工具为Unity（&lt;a href=&quot;http://www.codeplex.com/unity&quot;&gt;http://www.codeplex.com/unity&lt;/a&gt;）。因为获取UnityContainer是一个常用操作，所以我将其封装成一个辅助类，代码如下：&lt;/p&gt;
&lt;div class=&quot;cnblogs_code&quot;&gt;
&lt;pre&gt;&lt;div&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 1&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;/*&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;*********************************************************************&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 2&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 3&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 北京航空航天大学计算机学院软件工程研究所 All Rights Reservd&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 4&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 5&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 任何拷贝都不允许删除此处版权声明&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 6&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 7&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 作者：张洋&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 8&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 9&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 建立时间：2010-01-08&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;10&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;11&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * *******************************************************************&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;*/&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;12&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;13&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; System.Configuration;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;14&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;15&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; Microsoft.Practices.Unity;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;16&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; Microsoft.Practices.Unity.Configuration;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;17&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;18&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; SPMS.Common.Utils&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;19&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;20&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;21&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 工具类&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;22&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 封装了Unity中Container的创建工作，并保证Unity Container的单例性&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;23&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;24&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityHelper&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;25&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;26&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; IUnityContainer _container &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;27&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;28&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;29&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 获取Unity Container&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;30&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;31&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;全局唯一的Unity Container实例&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;32&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; IUnityContainer CreateContainer()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;33&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;34&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; _container)&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;35&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;36&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;                _container &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityContainer();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;37&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;38&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;从配置文件中读取IoC配置信息&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;39&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;                ExeConfigurationFileMap map &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; ExeConfigurationFileMap();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;40&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;                map.ExeConfigFilename &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;unity.cfg.xml&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;41&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;                Configuration config &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;42&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;43&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;通过配置信息初始化Container&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;44&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;                UnityConfigurationSection section &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; config.GetSection(&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;unity&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityConfigurationSection;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;45&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;                section.Containers[&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;defaultContainer&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;].Configure(_container);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;46&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;47&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;48&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; _container;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;49&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;50&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;51&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这段代码只有一个方法，就是CreateContainer，其作用是获取全局唯一的UnityContainer实例。在写完这个代码后，我开始写单元测试，我能想到有四个点要测：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）能正确返回UnityContainer&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）返回的UnityContainer能正确创建对象&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）保证创建的UnityContainer是单例的，即全局唯一实例&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4）返回的UnityContainer在创建配置为单例的对象时，返回的对象应该是单例的&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 有了这四点想法，我写了如下的单元测试：&lt;/p&gt;
&lt;div class=&quot;cnblogs_code&quot;&gt;
&lt;pre&gt;&lt;div&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 1&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;/*&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;*********************************************************************&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 2&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 3&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 北京航空航天大学计算机学院软件工程研究所 All Rights Reservd&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 4&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 5&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 任何拷贝都不允许删除此处版权声明&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 6&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 7&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 作者：张洋&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 8&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 9&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * 建立时间：2010-01-08&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;10&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;11&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt; * *******************************************************************&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;*/&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;12&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;13&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; NUnit.Framework;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;14&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;15&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; SPMS.Common.Utils;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;16&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; SPMS.Repository.IRepository;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;17&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; SPMS.Services.IServices;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;18&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;19&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; SPMS.XUnit.CommonTests&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;20&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;21&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;22&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; UnityHelper的单元测试类&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;23&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;24&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;    [TestFixture]&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;25&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityHelperTests&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;26&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;27&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;28&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 测试获取Container是否正常&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;29&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;30&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;        [Test]&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;31&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; TestCreateUnityContainer()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;32&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;33&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.IsNotNull(UnityHelper.CreateContainer());&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;34&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.IsInstanceOf(&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(Microsoft.Practices.Unity.IUnityContainer), UnityHelper.CreateContainer());&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;35&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;36&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;37&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;38&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 测试Container创建对象是否正常&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;39&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;40&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;        [Test]&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;41&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; TestCreateObject()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;42&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;43&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            IRoleRepository roleRepository &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityHelper.CreateContainer().Resolve&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IRoleRepository&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;44&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.IsNotNull(roleRepository);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;45&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.IsInstanceOf(&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(SPMS.Repository.NHibernateRepository.NHRoleRepository), roleRepository);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;46&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;47&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            IRoleServices roleServ &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; UnityHelper.CreateContainer().Resolve&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IRoleServices&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;48&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.IsNotNull(roleServ);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;49&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.IsInstanceOf(&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(SPMS.Services.ServicesImpls.RoleServicesImpl), roleServ);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;50&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;51&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;52&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;53&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 测试Container是否是单例对象&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;54&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;55&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;        [Test]&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;56&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; TestSingletonContainer()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;57&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;58&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.AreSame(UnityHelper.CreateContainer(), UnityHelper.CreateContainer());&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;59&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;60&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;61&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;62&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; 测试指定为Singleton的实例，是否为单例对象&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;63&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;///&lt;/span&gt;&lt;span style=&quot;color: #008000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;64&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;        [Test]&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;65&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; TestSingletonObject()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;66&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;67&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;            Assert.AreSame(UnityHelper.CreateContainer().Resolve&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IRoleRepository&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(), UnityHelper.CreateContainer().Resolve&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IRoleRepository&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;());&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;68&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;        }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;69&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;70&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 即使你没用过NUnit，我想这段代码也是非常好理解的。限于篇幅，不能详细介绍NUnit，这里只简要说一下。使用NUnit首先要添加对nunit.framework.dll的引用，然后引入NUnit.Framework命名空间，最后，每个测试类添加[TestFixture]Attribute，而每个测试方法添加[Test]Attribute，这样就可以在里面写测试代码了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 其中用的最多的是NUnit.Framework.Assert类，它有很多静态方法用于断言，这些断言就是你期望的行为。例如，Assert.AreSame方法断言两个变量是否引用同一个对象，我在上面代码里使用这个方法断言UnityContainer对象的单例性。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 完成这个单元测试代码后，要把测试需要的配置文件等添加到XUnit工程里，我这里包括一个unity.cfg.xml，作为Unity的配置文件。下面，编译这个工程。如果编译没有错误，下面就可以跑这个测试了。怎么跑呢，当你安装NUnit时，会同时安装一个NUnit GUI，在开始菜单中找到打开，界面大约是这样子：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010011223344870.gif&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;图2、NUnit GUI&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 选择菜单栏的 file -&amp;gt; open project ，打开刚才编译好的SPMS.XUnit.dll，也就是测试工程的dll文件，GUI会自动加载所有测试用例，如下图所示。&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010011223374355.gif&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;图3、加载工程后的NUnit GUI&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OK，我们要测试的是UnityHelperTests下的所有测试用例，所以我们在左边选中它，然后单击&amp;ldquo;run&amp;rdquo;按钮！这样GUI就会自动帮我们跑里面的测试用例了，最终结果如下。&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010011223410651.gif&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;图4、成功的测试结果&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以看到，所有UnityHelperTests的测试均为绿色，进度条也为绿色，且指示Passed: 4，这说明我们所有断言成功，测试通过。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面我们做点手脚，我在UnityHelper代码中取消了获取Container的单例性，现在再来运行测试看结果：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/201001/2010011223461562.gif&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;图5、失败的测试结果&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以看到，创建Container及创建Object是正常的，但Container的单例性被破坏。Container都不是单例的了，两个Object更不会是单例了。这时根据结果和右侧给出的错误信息，我们可以很快定位缺陷，并将之排除。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这个单元测试一但写好，开发团队中任何人员可以随时方便地跑它，这样我们就能在任何时刻知道UnityHelper是否工作正常，以帮助我们定位bug和排除缺陷。如果我们要做UnityHelper的重构，我们也可以使用它保证UnityHelper的行为正确。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 本文首先讨论了什么是单元测试，然后讨论了开发人员对单元测试的误解以及不愿做单元测试的原因。接着，我们讨论单元测试有哪些作用，最后用一个实际项目中的片段来说明单元测试的实践。限于篇幅，不能将单元测试及NUnit工具的方方面面讨论详尽，但是NUnit真是一个非常好上手的工具，你可以参考其文档和示例，或者参看Andrew Hunt所著的《Pragmatic Unit Testing in C# with NUnit》一书。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不论你是做何种开发，我相信，单元测试一定会让你受益匪浅。请相信，单元测试不是一件索然无味的工作，它同样充满了成就感和乐趣，每次看到鲜亮的绿色进度条，都是最爽的时刻。所以，希望看完本文的朋友能尽快拿起NUnit，开始你的单元测试实践。就从你的下一个项目、或下一个Class、甚至下一个Function，开始你的单元测试之旅吧。&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;a rel=&quot;license&quot; target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot;&gt;&lt;img align=&quot;left&quot; src=&quot;http://i.creativecommons.org/l/by/2.5/cn/88x31.png&quot; alt=&quot;Creative Commons License&quot; style=&quot;border-width: 0px;&quot; /&gt;&lt;/a&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;本文基于&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot; title=&quot;Creative Commons Attribution 2.5 China Mainland License&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;署名 2.5 中国大陆&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;许可协议发布，欢迎转载，演绎或用于商业目的，但是必须保留本文的署名&lt;/span&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;张洋&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;（包含链接）。如您有任何疑问或者授权方面的协商，请&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://space.cnblogs.com/msg/send/leoo2sk&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;给我留言&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;。&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1645561.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 28　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2010/01/13/pragmatic-unit-testing-with-nunit.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2010/01/13/pragmatic-unit-testing-with-nunit.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330716960/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2010/01/13/pragmatic-unit-testing-with-nunit.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330716960/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330716960/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 13 Jan 2010 00:02:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2010/01/13/pragmatic-unit-testing-with-nunit.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2010/01/13/pragmatic-unit-testing-with-nunit.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330716960/5313554</fs:itemid></item><item><title>从一道面试题谈linux下fork的运行机制</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html</link><description>&lt;p&gt;阅读: 1631 评论: 9 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-12-11 23:05 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 今天一位朋友去一个不错的外企面试linux开发职位，面试官出了一个如下的题目：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008080;&quot;&gt;给出如下C程序，在linux下使用gcc编译：&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;cnblogs_code&quot;&gt;
&lt;pre&gt;&lt;div&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 1&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;#include &lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;stdio.h&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 2&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;#include &lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;sys/types.h&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 3&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;#include &lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;unistd.h&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 4&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 5&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; main()&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 6&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 7&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    pid_t pid1;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 8&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    pid_t pid2;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt; 9&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;10&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    pid1 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; fork();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;11&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    pid2 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; fork();&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;12&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;13&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;    printf(&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;pid1:%d, pid2:%d\n&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;, pid1, pid2);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #008080;&quot;&gt;14&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #008080;&quot;&gt;要求如下：&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 已知从这个程序执行到这个程序的所有进程结束这个时间段内，没有其它新进程执行。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1、请说出执行这个程序后，将一共运行几个进程。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、如果其中一个进程的输出结果是&amp;ldquo;pid1:1001, pid2:1002&amp;rdquo;，写出其他进程的输出结果（不考虑进程执行顺序）。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 明显这道题的目的是考察linux下fork的执行机制。下面我们通过分析这个题目，谈谈linux下fork的运行机制。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;预备知识&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里先列出一些必要的预备知识，对linux下进程机制比较熟悉的朋友可以略过。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1、进程可以看做程序的一次执行过程。在linux下，每个进程有唯一的PID标识进程。PID是一个从1到32768的正整数，其中1一般是特殊进程init，其它进程从2开始依次编号。当用完32768后，从2重新开始。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、linux中有一个叫进程表的结构用来存储当前正在运行的进程。可以使用&amp;ldquo;ps aux&amp;rdquo;命令查看所有正在运行的进程。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3、进程在linux中呈树状结构，init为根节点，其它进程均有父进程，某进程的父进程就是启动这个进程的进程，这个进程叫做父进程的子进程。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4、fork的作用是复制一个与当前进程一样的进程。新进程的所有数据（变量、环境变量、程序计数器等）数值都和原进程一致，但是是一个全新的进程，并作为原进程的子进程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解题的关键&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 有了上面的预备知识，我们再来看看解题的关键。我认为，解题的关键就是要认识到fork将程序切成两段。看下图：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200912/2009121121573496.gif&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上图表示一个含有fork的程序，而fork语句可以看成将程序切为A、B两个部分。然后整个程序会如下运行：&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; step1、设由shell直接执行程序，生成了进程P。P执行完Part. A的所有代码。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; step2、当执行到pid = fork();时，P启动一个进程Q，Q是P的子进程，和P是同一个程序的进程。Q继承P的所有变量、环境变量、程序计数器的&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;当前&lt;/strong&gt;&lt;/span&gt;值。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; step3、在P进程中，fork()将Q的PID返回给变量pid，并继续执行Part. B的代码。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; step4、在进程Q中，将0赋给pid，并继续执行Part. B的代码。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里有三个点非常关键:&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff9900;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;1、P执行了所有程序，而Q只执行了Part. B，即fork()后面的程序。（这是因为Q继承了P的PC-程序计数器）&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #ff9900;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、Q继承了fork()语句执行时当前的环境，而不是程序的初始环境。&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #ff9900;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3、P中fork()语句启动子进程Q，并将Q的PID返回，而Q中的fork()语句不启动新进程，仅将0返回。&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;解题&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面利用上文阐述的知识进行解题。这里我把两个问题放在一起进行分析。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1、从shell中执行此程序，启动了一个进程，我们设这个进程为P0，设其PID为XXX（解题过程不需知道其PID）。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、当执行到pid1 = fork();时，P0启动一个子进程P1，由题目知P1的PID为1001。我们暂且不管P1。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3、P0中的fork返回1001给pid1，继续执行到pid2 = fork();，此时启动另一个新进程，设为P2，由题目知P2的PID为1002。同样暂且不管P2。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4、P0中的第二个fork返回1002给pid2，继续执行完后续程序，结束。所以，P0的结果为&amp;ldquo;pid1:1001, pid2:1002&amp;rdquo;。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5、再看P2，P2生成时，P0中pid1=1001，所以P2中pid1继承P0的1001，而作为子进程pid2=0。P2从第二个fork后开始执行，结束后输出&amp;ldquo;pid1:1001, pid2:0&amp;rdquo;。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6、接着看P1，P1中第一条fork返回0给pid1，然后接着执行后面的语句。而后面接着的语句是pid2 = fork();执行到这里，P1又产生了一个新进程，设为P3。先不管P3。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7、P1中第二条fork将P3的PID返回给pid2，由预备知识知P3的PID为1003，所以P1的pid2=1003。P1继续执行后续程序，结束，输出&amp;ldquo;pid1:0, pid2:1003&amp;rdquo;。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8、P3作为P1的子进程，继承P1中pid1=0，并且第二条fork将0返回给pid2，所以P3最后输出&amp;ldquo;pid1:0, pid2:0&amp;rdquo;。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 9、至此，整个执行过程完毕。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 所得答案：&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #339966;&quot;&gt;1、一共执行了四个进程。（P0, P1, P2, P3）&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #339966;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2、另外几个进程的输出分别为：&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #339966;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pid1:1001, pid2:0&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #339966;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pid1:0, pid2:1003&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #339966;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pid1:0, pid2:0&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 进一步可以给出一个以P0为根的进程树：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200912/2009121122414385.gif&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;验证&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面我们去linux下实际执行这个程序，来验证我们的答案。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 程序如下图：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200912/2009121122515562.png&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 用gcc编译、执行后结果如下：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200912/2009121122511552.png&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 由于我们不太可能刚巧碰上PID分配到1001的情况，所以具体数值可能和答案有所差别。不过将这里的2710看做基数的话，结果和我们上面的解答是一致的。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 应该说这不是一道特别难或特别刁钻的题目，但是由于fork函数运行机制的复杂性，造就了当两个fork并排时，问题就变得很复杂。解这个题的关键，一是要对linux下进程的机制有一定认识，二是抓住上文提到的几个关于fork的关键点。朋友说，这个题给的时间是5分钟，应该说时间还算充裕，但是在面试的场合下，还是很考验一个人对进程、fork的掌握程度和现场推理能力。&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 希望本文能帮助朋友们对fork的执行机制有一个明晰的认识。&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;a rel=&quot;license&quot; target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot;&gt;&lt;img align=&quot;left&quot; src=&quot;http://i.creativecommons.org/l/by/2.5/cn/88x31.png&quot; alt=&quot;Creative Commons License&quot; style=&quot;border-width: 0px;&quot; /&gt;&lt;/a&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;本文基于&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot; title=&quot;Creative Commons Attribution 2.5 China Mainland License&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;署名 2.5 中国大陆&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;许可协议发布，欢迎转载，演绎或用于商业目的，但是必须保留本文的署名&lt;/span&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;张洋&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;（包含链接）。如您有任何疑问或者授权方面的协商，请&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://space.cnblogs.com/msg/send/leoo2sk&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;给我留言&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;。&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1622212.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 9　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717003/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717003/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717003/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 11 Dec 2009 23:05:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717003/5313554</fs:itemid></item><item><title>细说业务逻辑（后篇）</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/10/31/1593740.html</link><description>&lt;p&gt;阅读: 2608 评论: 44 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-10-31 23:39 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/31/1593740.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;前篇：&lt;/strong&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html&quot; title=&quot;view: 细说业务逻辑（前篇）&quot; id=&quot;Editor_Edit_hlEntryLink&quot;&gt;&lt;span style=&quot;color: #002c99;&quot;&gt;http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;3、业务逻辑的架构模式及实现&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Martin Fowler在《Patterns of Enterprise Application Architecture》一书中，总结了四种企业应用中业务逻辑的组织方式 ：Transcation Script，Domain Model，Table Module及Service Layer，另外，本书的第十章&amp;ldquo;Data Source Architecture Patterns&amp;rdquo;中包含一种模式&amp;mdash;&amp;mdash;Active Record。结合软件体系结构的近期发展及个人的理解，我更倾向将Active Record归入业务逻辑的组织模式，而Service Layer应该不算做业务逻辑特有的模式，所以，在本文中，将介绍四种模式：Transcation Script，Table Module，Active Record及Domain Model。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1、Transction Script&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;3.1.1、概述&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Transction Script（以下简称TS）是一种面向过程的业务逻辑组织方式。这里首先要强调一点，这里的Transction一词与数据库系统中表示&amp;ldquo;事务&amp;rdquo;的Transction没有任何联系。&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;TS是将领域中的业务分解为一个个业务过程，每个过程实现一项业务功能，具体到程序中，一个业务过程往往映射到一个方法。TS是完全面向过程的业务组织模式，适合应用于业务逻辑较简单的场合。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 应该说，我们见到的绝大多数系统都是以TS组织业务的。例如PetShop及Oxite等经典示例。有时为了方便维护，开发者会将同一领域实体相关的业务方法集中到一个类中，这里虽然用到了领域实体和类的概念，但和面向对象没有任何关系，完全是面向过程的。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 当使用TS时，可以不需要数据访问层，而是将数据操作执行代码（如执行SQL或存储过程的代码）直接嵌入在业务方法中，有时为了复用性和维护性可以编写一个helper类封装数据库的操作。当然这并不是说TS不能配合数据访问层使用，但由于应用TS的场合一般业务非常简单，如果配合Repository或ORM使用，业务逻辑层往往就会变得非常&amp;ldquo;瘦&amp;rdquo;，看起来仅仅是对数据访问层的封装。一般在需要支持多数据库的场合，要配合Repository和Abstract Factory使用。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TS的示意图如下所示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-1_2.gif&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;438&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-1_thumb.gif&quot; alt=&quot;图3-1&quot; height=&quot;535&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px;&quot; title=&quot;图3-1&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;strong&gt;图3-1、 Transcation Script架构示意&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以看到，在TS中，业务层并没有面向对象的东西。也许会用到类，但类只是组织业务方法的模块，每个模块中有一个个业务方法，每个业务方法完成一个业务流程，完全按面向过程结构组织。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;3.1.2、分析&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;什么时候可以用TS？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 应该说，如果具备以下条件&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;之一&lt;/span&gt;&lt;/strong&gt;，你可以考虑TS：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）系统业务十分简单直观，并且频繁变动的可能性不大&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）工期很紧，需要尽量压缩设计的时间，尽快投入编码&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）不能熟练掌握和使用OO进行系统的设计与开发&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4）厌恶OO，就是喜欢面向过程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;TS的优点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）设计阶段投入较小，启动耗费低。因为TS较容易掌握，使用起点低，所以使用TS的初期投入较少&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）在业务比较简单直观的情况下，TS结构的代码直观易懂，具有良好的可维护性&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;TS的缺点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）容易造成代码冗余。因为各个业务自行组织流程，所以减少了复用的机会，可能产生重复性代码&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）因为TS天生不适合业务复杂的系统，当系统业务较复杂时，可能会令业务层代码繁杂不堪&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.2、Table Module&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.2.1、概述&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Table Module（以下简称TM）同样是一种面向过程的业务逻辑组织方式，与TS不同的是，TM更贴近关系型数据库结构。&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;在TS中，一般使用DTO等进行数据表示和传递，其着眼点一般在单个对象。而TM一般根据数据表组织业务模块，每个模块对应一个表，其中包含了这个表的相应处理。并且在业务层内，使用库-表结构的对象进行数据操作，做到最大限度与数据表的对应。业务组织一般按照面向过程组织。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一般当业务相对简单且业务基本集中在CRUD操作时，可以考虑TM。使用TM意味着使用数据驱动设计。通常自己实现一套库-表结构操作对象的库是难度比较大的，所以一般选用TM时，所使用的平台应该包括这么一套库。如.NET平台上的ADO.net就内置了丰富的库-表操作，DataSet，DataTable，DataAdapter等在TM架构的实现中可以起到非常方便的作用。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 使用TM后，一般不需要再配合Reponsitory或ORM，因为此时的业务层也是面向过程和面向关系型结构的，无须映射。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TM的示意图如下：&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-2_2.gif&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;438&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-2_thumb.gif&quot; alt=&quot;图3-2&quot; height=&quot;535&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;&quot; title=&quot;图3-2&quot; /&gt;&lt;/a&gt;&lt;strong&gt;图3-2、Table Module架构示意&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在使用TM后，业务代码中往往有各种对象对应数据库中的库、表、记录、字段等元素，并提供类似关系数据库的操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.2.2、分析&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;什么时候可以用TM？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;同时&lt;/strong&gt;&lt;/span&gt;具备以下条件，你可以考虑TM：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）系统业务较直观，以CRUD操作比较集中&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）整个开发的指导思想是数据驱动&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）所选用的平台有成熟的库-表操作库支持&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;TM的优点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）类似关系数据库的数据操作方式非常直观，使得设计和编写数据操作功能的代码简单高效&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;TM的缺点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）TM需要完全的数据驱动，从业务到UI传递、存放数据都要以表结构形式，造成一定程度上的不灵活&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）当业务并非CRUD集中型操作，特别是领域模型和数据库表模型差异较大时，使用TM组织业务的难度非常大&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3、Active Record&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3.1、概述&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Active Record（以下简称AR）是一种面向对象的业务逻辑组织方式。AR适用于在业务较简单的情况下，应用面向对象思想进行设计。&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;它的基本思想就是将领域中每个实体抽象出一个业务类（BO），然后，将这个实体的数据和行为封装成类的属性和方法。特别的，将CRUD功能也封装进BO中。也就是说，AR中的BO同时具备业务方法和持久化功能。其本身具有ORM的特性，其内部要处理关系实体间的关联问题。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 使用AR时，一般最好有相应框架支持，否则完全手工实现AR有点麻烦。像Castle框架中就有AR功能，Linq to sql也有AR的意思。使用AR后，一般不需要再单独使用数据访问层。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AR的组织架构如下图：&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-3_2.gif&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;514&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-3_thumb.gif&quot; alt=&quot;图3-3&quot; height=&quot;486&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;&quot; title=&quot;图3-3&quot; /&gt;&lt;/a&gt;&amp;nbsp;&lt;strong&gt;图3-3、Active Record架构示意&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 从图3-3中可以看出，AR对业务领域进行了一个简单的OO抽象，将各个实体抽象为AR业务对象，AR业务对象内含有数据、业务方法及数据访问相关的ORM方法。另外，AR业务对象要维护实体间简单的一对多和多对多等关系。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3.2、分析&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;什么时候可以用AR？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;同时&lt;/span&gt;&lt;/strong&gt;具备以下条件，你可以考虑AR： &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）系统业务较直观&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）想尝试使用或习惯于使用OO进行系统设计与实现&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）平台上有成熟的AR框架可以用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;AR的优点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）使用OO的方式进行设计与实现，能在一定程度上避免冗余代码问题）&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）使用AR后，与某个实体相关的数据和业务全部集中于AR业务对象中，模块内聚性好，便于维护&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）实践证明，AR结构的业务层编码效率很高&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;AR的缺点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）AR仍需要关注数据之间的关联，在一定程度上带有数据表和影子，没有完全摆脱数据驱动，所以当业务领域和数据库结构差距大时，实施困难&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）AR的CRUD是以个体为粒度的，当进行批量操作时，如一次查数千个数据，如果严格尊从AR就需要生成数千个AR业务对象，这简直是场灾难。所以在有大规模查询的情况下，可以考虑使用TS配合AR&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）如果业务非常复杂，AR将力不从心&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.4、Domain Model&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.4.1、概述&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Domain Model（以下简称DM）是一种适合领域驱动和为复杂业务系统组织业务的面向对象业务逻辑组织方式。前面三种架构模式都有一个共同的缺点&amp;mdash;&amp;mdash;不适合业务复杂的系统。那么何为复杂何为简单？很抱歉，我给不出明确答案，而且我估计世界上任何一个人都很难给出标准的无争议答案。因为软件系统中的复杂和简单本身就是一个难以量化的指标，很多时候，只能靠专业人员的经验了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我个人估计，世界上95%的软件系统其业务难度都不会超出上述三种模式的能力范围，而若你不幸遇到剩下的5%，恐怕目前只有Domain Model能帮你了。&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Domain Model是一种纯面向对象的业务架构模式，它的核心思想是获取领域中的各种实体抽象，然后完全按照现实领域中的情况去建模和运行。并且业务对象是&amp;ldquo;持久化无知&amp;rdquo;的。&lt;/strong&gt;&lt;/span&gt;关于&amp;ldquo;持久化无知&amp;rdquo;下面细讨论。这个模式十分复杂和难以掌握，但一旦掌握并使用，其能力绝对会超乎你的想象。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面看一下DM的架构示意图：&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;&lt;img border=&quot;0&quot; width=&quot;590&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-4_thumb_1.gif&quot; alt=&quot;图3-4&quot; height=&quot;608&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px;&quot; title=&quot;图3-4&quot; /&gt;&amp;nbsp; 图3-4、Domain Model架构示意&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 从图3-4中可以看出，DM看上去是个十分纠结的模式，而实际上，它确实很纠结！实际上，我认为如果能熟练掌握并运用DM进行业务逻辑的组织，那这人绝对是架构师中的大师级人物（我目前是做不到）。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 还是先结合图示分析一下DM中的要点。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第一，DM中的业务对象是纯业务对象，不含数据访问操作。这个可以和AR中的业务对象对比一下。也就是说，DM中的业务对象是纯业务对象，它们只关注与业务的实现。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第二，DM的组织内部对象多，关系复杂，而这种关系不再只是那种简单的一对一、一对多的关系，而是领域中的各种依赖和关联的抽象，关系类型多，非常复杂。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第三，DM需要业务部分&amp;ldquo;持久化无知&amp;rdquo;。所谓持久化无知，指业务部分只需执行业务功能，而不必关系持久化。在使用DM时，必须设计一套ORM机制（注意这里用到了&amp;ldquo;机制&amp;rdquo;一词，而不是&amp;ldquo;框架&amp;rdquo;或&amp;ldquo;库&amp;rdquo;），使得在业务系统运行时，自动在必要的时候执行数据持久化操作。这也是为什么上图数据源和业务层间的箭头是虚线的关系。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上文曾说过，DM要最大程度模拟现实情况。而现实世界和软件世界最大的区别就是现实世界是&amp;ldquo;内存无限大、永不停机的&amp;rdquo;，可以把现实世界看成在一个无限大内存里永不停止运行的程序。而软件世界不同，它的内存有限制，我们不能将所有对象都放在内存，而且一旦掉电，它就会停止运行，正因如此，我们才需要持久化机制去配合DM模拟现实世界。为了让业务更接近现实，它必须对持久化过程毫无感觉。而一套持久化机制默默为其营造了一个好似内存无限大、永不停机的环境，因此DM才得以发挥威力。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第四，DM往往需要Services Layer的配合。因为DM内部仅有一个个业务对象，它们互相调用，并没有提供一个友好的接口与UI交互，所以在使用DM时，往往在其上对各种UI需要的服务进行封装（回顾一下Facade模式），形成一个Services Layer，以方便与UI交互。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.4.2、分析&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;什么时候可以用DM？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;同时&lt;/span&gt;&lt;/strong&gt;具备以下条件，你可以考虑DM： &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）系统业务极为复杂 &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）有功底扎实和经验丰富的精通OO的架构及设计师&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）项目经费和时间充足 &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4）贯彻领域驱动设计&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;DM的优点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）完全的OO思想运用，将使你享受到OO的所有优势&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）应付复杂业务的强力杀手锏。如果DM运用得当，将会使得复杂业务被高效解决&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;DM的缺点？&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）使用门槛极高，难度极大，如果团队中没有精通OO和系统架构且经验丰富的专家很难实施 &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）设计过程极为复杂，可能会导致设计瘫痪&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）如何设计良好的ORM机制辅助DM是一大难题&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.5、各种架构模式的比较及选择&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 相信看过上文内容后，各位一定对各种业务组织模式及其特点、优劣、应用场景有了清晰地认识，如果我在这里再喋喋不休讨论各种模式的比较及如何选择，难免有侮辱各位智商之嫌O(&amp;cap;_&amp;cap;)O~，所以这里我只给大家呈现一幅决策网络图，以期起到一个梳理和归纳总结的作用。&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;760&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/be59e88db510_D6CC/%E5%9B%BE3-5_thumb.gif&quot; alt=&quot;图3-5&quot; height=&quot;610&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px;&quot; title=&quot;图3-5&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;图3-5、业务架构模式决策网络&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #8000ff;&quot;&gt;&lt;strong&gt;（郑重声明：图3-5为本人原创，并非摘录自已有文献，因此此图的选型流程仅代表个人意见。由于笔者水平有限，不能保证此图一定合理和正确。因此在实际选型时请多多参考已有文献及咨询相关专家，此图只起总结归纳和探讨作用，不作为任何指导和规范。若因遵循此图选型而给项目带来的任何经济及其他方面损失，笔者不承担任何责任。）&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4、结束语&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 本文通过两篇文章的篇幅，先后介绍了业务逻辑的定义、相关理论及经典的业务逻辑相关的架构模式。本文中阐述了不少已有理论，亦掺杂诸多个人理解及看法。因此请各位在阅读时多进行批判吸收，同时参考以后经典文献及书目综合理解业务逻辑，切勿仅看我一家之言。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 另外，由于本文仅仅是综述性文章，不能具名业务逻辑的各个方面，在深度上也基本是浅尝辄止。因此，若希望深入理解业务逻辑，可以看到相关经典书籍及文献。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参考文献&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;[1] [意]Dino Esposito, Andrea Saltarello, .NET软件架构之美英文版(原名Microsoft .NET Architecting Application for the Enterprise), 人民邮电出版社, 2009&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;[2] [美]Martin Fowler, 企业应用架构模式影印版(原名Patterns of Enterprise Application Architecture), 中国电力出版社, 2004&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;[3] [美]Mclaughlin, Pollice, West, 深入浅出面向对象分析与设计影印版(原名Head First OOA&amp;amp;D), 东南大学出版社, 2007&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;[4] Google, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://www.google.com&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;www.google.com&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;a rel=&quot;license&quot; target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot;&gt;&lt;img align=&quot;left&quot; src=&quot;http://i.creativecommons.org/l/by/2.5/cn/88x31.png&quot; alt=&quot;Creative Commons License&quot; style=&quot;border-width: 0px;&quot; /&gt;&lt;/a&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;本文基于&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot; title=&quot;Creative Commons Attribution 2.5 China Mainland License&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;署名 2.5 中国大陆&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;许可协议发布，欢迎转载，演绎或用于商业目的，但是必须保留本文的署名&lt;/span&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;张洋&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;（包含链接）。如您有任何疑问或者授权方面的协商，请&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://space.cnblogs.com/msg/send/leoo2sk&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;给我留言&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;。&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1593740.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 44　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/31/1593740.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/31/1593740.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717358/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/10/31/1593740.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717358/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717358/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 31 Oct 2009 23:39:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/10/31/1593740.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/10/31/1593740.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717358/5313554</fs:itemid></item><item><title>细说业务逻辑（前篇）</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html</link><description>&lt;p&gt;阅读: 3538 评论: 77 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-10-29 21:51 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;前言&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 记得几个月前，在一次北京博客园俱乐部的活动上，最后一个环节是话题自由讨论。就是提几个话题，然后大家各自加入感兴趣的话题小组，进行自由讨论。当时金色海洋同学提出了一个话题&amp;mdash;&amp;mdash;&amp;ldquo;什么是业务逻辑&amp;rdquo;。当时我和大家讨论ASP.NET MVC的相关话题去了，就没能加入&amp;ldquo;业务逻辑&amp;rdquo;组的讨论，比较遗憾。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 其实，一段时间内，我脑子里对&amp;ldquo;业务逻辑&amp;rdquo;的概念也是非常模糊的。但在不断地阅读、思考和实践过程中，这个概念及其相关的内容才在我脑子里渐渐清晰。我想，很多朋友也许也对这个概念不是很了解，所以愿意结合既有资料和自己的思考，总结一篇关于业务逻辑的概述性文章，一则与朋友们分享探讨，二则也是为自己对业务逻辑的学习做一个总结和提升。因为我还不敢说对业务逻辑内涵及外延理解的非常充分，所以文中如有不当之处，还请各位不用客气，尽管批评就好！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;内容提要&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;&lt;strong&gt;===================&lt;span style=&quot;color: #004080;&quot;&gt;前篇=====================&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 前言&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 内容提要&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1、我把业务逻辑丢了！&amp;mdash;&amp;mdash;找回丢失的业务逻辑&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2、细说业务逻辑&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.1、业务逻辑到底是什么&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.2、业务逻辑的组成结构&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.2.1、领域实体（Domain Entity）&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.2.2、业务规则（Business Rules）&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.2.3、完整性约束（Validation）&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.2.4、业务流程及工作流（Business Processes and Workflows）&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.3、业务逻辑层职责相关争议&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.3.1、争议一：数据的格式化&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.3.2、争议二：数据合法性及完整性验证&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.3.3、争议三：CRUD&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 2.3.4、争议四：存储过程&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;===================&lt;span style=&quot;color: #004080;&quot;&gt;后篇=====================&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3、业务逻辑的架构模式及实现&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.1、Transcaton Script&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.1.1、概述&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.1.2、分析&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.2、Table Module&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.2.1、概述&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.2.2、分析&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.3、Active Record&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.3.1、概述&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.3.2、分析&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.4、Domain Model&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.4.1、概述&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&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;&amp;nbsp; 3.4.2、分析&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.5、各种架构模式的比较及选择&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4、结束语&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #004080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 参考文献&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;1、我把业务逻辑丢了！&amp;mdash;&amp;mdash;找回丢失的业务逻辑&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 相信朋友们基本都是软件开发人员。不论身处什么职位，我们的工作都有一个共同的目标&amp;mdash;&amp;mdash;制作软件产品。而&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;所谓的软件产品，一定是在某个领域内去实现某些业务&lt;/strong&gt;&lt;/span&gt;。如此看来，&amp;ldquo;业务逻辑&amp;rdquo;本应和&amp;ldquo;软件产品&amp;rdquo;是紧紧绑在一起的，没有业务逻辑，何来软件产品？&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 但是，我发现一个奇怪的现象，一说业务逻辑，很多人就无法形成清晰地印象。例如，经典的三层架构：表示层、业务逻辑层和数据访问层，一提到表示层或数据访问层，大家脑子里马上能产生出清晰的概念，但一提到业务逻辑层，就有点模糊了，或者完全不知道其是什么，或者有个模糊的轮廓，但对其具体的职责、结构不是很清楚。真是奇了怪了！我们天天和业务逻辑打交道，搞不清业务逻辑是什么。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 对于这个奇怪的现象，我思前想后，结合自身的教训（我也曾很长时间搞不清业务逻辑），终于弄清楚了其原因&amp;mdash;&amp;mdash;这和我们接触这个概念的途径和认知结构有莫大关系。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不知道有多少人和我一样，首次接触&amp;ldquo;业务逻辑&amp;rdquo;这个概念是从分层架构中的&amp;ldquo;业务逻辑层&amp;rdquo;概念开始的，我相信不在少数。事情坏就坏在这里！为了让朋友们直观看清&amp;ldquo;业务逻辑&amp;rdquo;的概念是怎么被我们丢掉的，请大家看一个图，这个图展示了很多人对&amp;ldquo;业务逻辑&amp;rdquo;的认知过程。&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;721&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/bccd7090a403_D257/%E5%9B%BE1-1_thumb.gif&quot; alt=&quot;图1-1&quot; height=&quot;294&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; border-width: 0px;&quot; title=&quot;图1-1&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;font-size: small;&quot;&gt;图1-1、狭义的认知分解过程&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如图1-1所示，我们先接触了分层架构，然后对每个层产生了初步的认识。其中，由于表示层和数据访问层的代码职责清晰明确，基本能正确认识。但是，由于我们接触的分层架构的Demo大多业务极其简单，又基本是CRUD操作集中型的业务。所以，我们脑子中就产生了疑问：这个所谓的业务逻辑层是干什么的？怎么就简单封装了一下数据访问层的操作？这有存在的必要吗？由于有了这种&amp;ldquo;先入为主&amp;rdquo;的误导，使得很多朋友脑中将&amp;ldquo;业务逻辑&amp;rdquo;和&amp;ldquo;业务逻辑层&amp;rdquo;两个概念混淆了，始终想不明白这东西到底是什么，做什么用的。再加上很多朋友所看的、所做的系统都是CRUD操作集中型的，就形成了&amp;ldquo;业务逻辑貌似就是对数据访问操作的简单封装&amp;rdquo;这一片面概念。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 到底这一概念有没有错呢？其实没错，因为在简单的、CRUD操作集中型软件中，业务逻辑基本就是对数据访问简单的封装。但是，无错不代表全面，这是一种狭义的业务逻辑理解，而且是狭义中的狭义。为什么这么说呢？因为我们不但是在&amp;ldquo;业务逻辑层&amp;rdquo;这么一个狭义范围内去理解业务逻辑，而且还是CRUD集中型操作这种&amp;ldquo;非常瘦&amp;rdquo;的业务逻辑层范围内去理解，所以，可谓是在狭义的基础上的狭义。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;当我们把这么一个&amp;ldquo;狭义中的狭义业务逻辑&amp;rdquo;与&amp;ldquo;业务逻辑&amp;rdquo;等同起来时，误会、迷茫、困惑、不屑就出现了。这就如同，给你一只温顺的哈巴狗，还是病怏怏的、无精打采的小哈巴狗，而你把这只&amp;ldquo;病怏怏的小哈巴狗&amp;rdquo;与&amp;ldquo;狗&amp;rdquo;的概念等同起来了。那么你一定就会为有人养狗看家和警察养狗当警犬抓坏人而困惑：这东西这么弱小，我一脚就踩死了，怎么弄用来看家和抓坏人呢？进而可能会产生&amp;ldquo;狗狗无用论&amp;rdquo;，&amp;ldquo;狗狗废品&amp;rdquo;等观念。当然，在现实中，很少有人只见过小哈巴狗而没见过狼狗等其它狗类，所以，故事中的误会对&amp;ldquo;狗&amp;rdquo;一般是不存在的。但在现实中，确实有很多人只见过业务逻辑中的&amp;ldquo;小哈巴狗&amp;rdquo;，却没有见过业务逻辑中的&amp;ldquo;狼狗&amp;rdquo;、&amp;ldquo;藏獒&amp;rdquo;，所以，这种误会在对&amp;ldquo;业务逻辑&amp;rdquo;的理解上广泛存在。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 那么，广义的情况究竟是怎么样的？请看下图。&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;590&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/bccd7090a403_D257/%E5%9B%BE1-2_thumb.gif&quot; alt=&quot;图1-2&quot; height=&quot;344&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; border-width: 0px;&quot; title=&quot;图1-2&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;font-size: small;&quot;&gt;图1-2、广义的认知分解过程&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; （注意！凡是不特别说明，下文中所有&amp;ldquo;数据&amp;rdquo;一词都指需要持久化的数据，而不包括内存中的临时数据。请各位留心。）&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如图1-2所示，广义的认知分解应该是这样的：&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;软件产品都是在某个领域内实现某些特定业务，所以，软件产品天生应该分解为界面交互部分和业务逻辑部分，其中业务逻辑部分是软件产品的核心，它客观存在于软件产品内部，但是无法对使用者产生直观刺激，因此业务逻辑不能与使用者直接交互。而界面交互部分是业务逻辑与使用者进行交流的接口，使用者通过界面交互部分，与业务进行交流，从而使得软件产品发挥其作用。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 而在具体实现系统时，界面交互部分演化成表示层，业务逻辑部分演化成业务逻辑层。所以，可以认为，数据访问层不是软件产品自然演化的直接产物，之所以出现数据访问层，是因为某些产品的业务属于&amp;ldquo;数据操作集中型&amp;rdquo;业务，为了实现隔离、复用等目的，架构师从业务逻辑中分离出了频繁使用的数据访问业务，形成了单独的数据访问层。从广义来说，可以认为数据访问隶属于业务逻辑，因为，数据访问操作实际上也是业务逻辑的一部分。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 总结一下几个要点：（这几个要中的业务逻辑均指广义业务逻辑）&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #0080ff;&quot;&gt;1）软件产品自然的可分为界面交互部分和业务逻辑部分。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080ff;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）从空间结构上看，业务逻辑和数据访问不是并列关系，而是隶属关系&amp;mdash;&amp;mdash;数据访问隶属于业务逻辑。虽然在具体系统实现层面，数据访问层和业务逻辑层是并列存在，但从概念本质层面上分析，两者是隶属关系。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080ff;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）从时间结构上看，应该是先有业务逻辑的概念，才有数据访问的概念。业务逻辑衍生自软件本身，数据访问衍生自业务逻辑。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080ff;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4）因为业务逻辑是软件产品自然的一部分，所以拥有业务逻辑是软件产品的必要条件（读者可以试着举出一个不包含业务逻辑的软件）。但是一个软件可以没有数据访问，如&amp;ldquo;计算器&amp;rdquo;、&amp;ldquo;不带存档的小游戏&amp;rdquo;等。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 利用以上论述要点和认知分解，朋友们可以试试在脑中重新构筑狭义和广义&amp;ldquo;业务逻辑&amp;rdquo;的概念。看能不能把我们丢掉的业务逻辑概念找回来。关于业务逻辑更多的细节，将在下文中讨论。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;2、细说业务逻辑&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.1、业务逻辑到底是什么&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在第一大节里说了那么多，相信各位基本已经形成&amp;ldquo;业务逻辑&amp;rdquo;的概念了。如果我在这里再啰嗦什么，我不嫌累各位也要嫌烦了。所以，这里我仅给出两个定义。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;广义上的义务逻辑&amp;mdash;&amp;mdash;软件本身固有的一种品性，自然存在于软件产品内部，是软件具有的在某个业务领域内的逻辑，是软件的核心和灵魂。软件产品除界面和交互外的一切都可看作是广义业务逻辑。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 狭义上的业务逻辑&amp;mdash;&amp;mdash;等同于分层架构中&amp;ldquo;业务逻辑层&amp;rdquo;的职责，是软件中处理与业务相关任务的部分，一般狭义上的业务逻辑不包含数据持久化，而只关注领域内的相关业务。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 对于以上两种定义，希望朋友们不要割裂开来看，而 要辩证统一的去看，这样，才能构建一个完整而辩证统一的&amp;ldquo;业务逻辑&amp;rdquo;概念。在下文中，将不再明确区分狭义和广义，&amp;ldquo;业务逻辑&amp;rdquo;一词将代表两者的辩证统一体。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.2、业务逻辑的组成结构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 业务逻辑作为一个高层次概念，其内在结构也是非常丰富的，下面我们深入其里，去探寻一下业务逻辑都是由哪些更底层的部分构成的。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.2.1、领域实体（Domain Entity）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 通俗的说，领域实体就是这个领域内有哪些东西。例如，银行业领域内有账户、支票、前台营业员等实体；B2C电子商务领域有商品、订单、交易等实体；魔兽世界游戏的领域内有角色、种族、道具、魔法等实体；高等代数领域有矩阵、行列式等实体。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;领域实体是某个领域内各种对象的抽象，可以用名词表示（可以是具体名词或抽象名词，甚至动名词，只要其具有名词性），构成了整个业务逻辑的骨骼和静态模型。一般每个领域实体有自己的一些属性和行为。&lt;/strong&gt;&lt;/span&gt;顺便说一句，领域实体的存在时OOA&amp;amp;D的基础。 &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在具体的软件系统中，领域实体往往会根据架构的不同有不同的映射存在形式。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 其中一种叫做Business Object（BO），即业务对象，某些文献称其为&amp;ldquo;充血实体类&amp;rdquo;，这种对象完整抽象了领域内的某个实体，封装了此实体相关属性和行为。在面向对象的设计和架构中，这种实体类很常见。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 另一种叫做Data Transfer Object（DTO），某些文献称其为&amp;ldquo;贫血实体类&amp;rdquo;，其特点是仅有属性，不存在行为。这种实体类主要负责整体性传递数据。另外，与BO不同的是，DTO可以不抽象领域实体的全部属性，而只根据需要抽象一部分。例如，某个&amp;ldquo;User&amp;rdquo;实体存在很多属性，但如果某个方法仅需要其联系方式，可以设计一个DTO，仅有id，email，address，phone等就够了。在面向过程的设计和架构中，这种实体设计比较常见。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.2.2、业务规则（Business Rules）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;业务规则就是某个领域内运作的规则，构成了整个业务逻辑的灵魂和动态模型。业务规则作用于领域实体，领域实体遵从业务规则进行运作。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如：在银行领域内，&amp;ldquo;转账时从A账户扣除相应款项，在B账户添加相应款项，并从A账户扣除相应手续费，并通过某些途径通知A和B账户的户主&amp;rdquo;就是一条规则。需要注意的是，业务规则比较抽象，并不是需求，需求需要具体且无二义性，而业务规则只是抽象的一种描述，例如，通知户主的途径是什么？电子邮件？电话？短信？并没有具体描述，但在规则中有&amp;ldquo;通知&amp;rdquo;这一项，因此不能将业务规则等同于需求。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.2.3、完整性约束（Validation）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;领域实体和业务规则构建了业务逻辑的主体，但在这主体之上，还存在着一个限制，这就是完整性约束。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 完整性约束是对业务领域中的数据、规则的强制性规定与约束。这种约束是系统正常运转的保证。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如&amp;ldquo;账户密码不能为空&amp;rdquo;，&amp;ldquo;身份证号必须符合具体格式规定&amp;rdquo;，&amp;ldquo;转账流程必须具有原子性，A账户扣钱、B账户存钱、A账户扣除手续费、通知户主四项操作必须要么都做，要么都不做&amp;rdquo;，都是完整性约束。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.2.4、业务流程及工作流（Business Processes and Workflows）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 有了上述三项，业务逻辑还不能正常工作，因为还没有&amp;ldquo;启动器&amp;rdquo;和&amp;ldquo;过程托管器&amp;rdquo;。设想我们有了各种实体类，它们有各自的属性和行为，也有定义好的业务规则和完整性约束。现在实体类仅仅具有实现业务规则的能力，但它们如何启动并交互协调完成业务规则呢？因此我们需要有东西去触发和协调实体。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 业务流程或工作流是启动及托管协调领域实体完成既定规则的过程。例如，&amp;ldquo;在线订购&amp;rdquo;是一个业务流程，它包括&amp;ldquo;用户登录-选择商品-结算-下订单-付款-确认收货&amp;rdquo;这一系列流程。各个实体如会员、订单、商品等已经包含了完成在线订购必要的行为，但仍需一个流程，才能真正完成业务。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 具体到程序中，业务流程也许通过一个方法来实现，这个方法负责启动并协调各个实体类，完成一个流程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.3、业务逻辑层职责及相关争议&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.3.1、数据的格式化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 关于数据的格式化应该放在业务层进行还是表示层进行一直存在争议。我个人的意见是这样的：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 业务层送给表示层的数据应该具备以下要求。&lt;span style=&quot;color: #888888;&quot;&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;1）返回的数据应该完成了所有必要的业务处理和业务计算。&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;例如，若返回订单信息让表示层展示，会有个必要的数据&amp;mdash;&amp;mdash;订单总额。这个数据需要首先用各个订单项的单价乘以数量，然后加和。那么，这个数据应该在业务层完成计算直接返回，总之不应让表示层进行任何业务处理和计算操作。&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;2）一次性返回所有需要的数据，避免表示层再一个Action里调用多次业务。&lt;/strong&gt;&lt;/span&gt;打个比方，例如订单中有个&amp;ldquo;客户姓名&amp;rdquo;，这个数据不保存在订单表中，而是通过外键关联的，那么，业务层应该将&amp;ldquo;客户姓名&amp;rdquo;一并取出返回给表示层。总之，避免表示层在一个Action里多次调用业务层。&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;3）不携带任何格式信息，仅仅是结构良好的纯净数据，如DTO形式。&lt;/strong&gt;&lt;/span&gt;因为，数据如何展示，是表示层的职责，如何在业务层中返回了过多格式信息，就会造成表示层的修改困难。例如，我曾听说过所里承接的一个实际项目，开始是使用B/S，当时他们的业务层返回的数据全都附带了html代码。后来，客户嫌B/S响应不够迅速（可能是客户公司的网络条件不好），要求改成C/S，当时全傻眼了，貌似几乎修改了整个业务层。那个项目相当庞大，7个子系统，投入200人开发了1年多，想想修改的难度吧。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.3.2、数据合法性及完整性验证&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一般做系统，都避免不了数据验证。上文曾经提到，完整性约束是业务逻辑的一部分。如此看来，数据验证一般应该放在业务层。但是，实际情况并不尽然。个人认为数据验证的方式，目前没有统一标准，可以根据需要放在表示层或业务层。但是，我个人不提倡在&amp;ldquo;表示层的服务端&amp;rdquo;放置过多完整性验证。因为，表示层的职责应该仅仅是接收数据并传递给业务层，不应对数据是否合法负责。过多的数据验证，不但令表示层代码臃肿，而且使得表示层职责变得不明确。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 可以在&amp;ldquo;表示层的服务端&amp;rdquo;放置一些简单的验证，如空值验证，两次输入密码是否一致等，但业务关系紧密的验证，最好放在业务层。甚至有些验证只能在业务层验证，如&amp;ldquo;当前用户名不能与已有用户名重复&amp;rdquo;，这种验证需要访问持久化数据，需要由业务层完成。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里之所以强调&amp;ldquo;表示层的服务端&amp;rdquo;，是因为一般在B/S系统中，都会在JavaScript里加入一些基本的数据验证，如空值检查，格式正则匹配等。这主要是为了减轻服务器负担，将大多数显然包含不合法数据的请求拒绝掉，而不发给服务端验证。当然，因为可能会出现JS被屏蔽或黑客恶意攻击行为，所以，所有验证不论JS中是否验证过，服务端（可能是表示层的服务端部分或业务层）一定要再进行验证。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.3.3、CRUD&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CRUD，即常说的增删改查操作。关于CRUD是否是业务层的职责，一直也是争议不断。因为目前并没有权威的定义，所以这里我斗胆说一下我对这个问题的看法。还请大家批判性阅读。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一说到&amp;ldquo;增删改查&amp;rdquo;，大家一定会觉得这理所当然是数据访问层的职责。我认为这个理解是对的，但是只对了一半！之所以这么说，是因为&amp;ldquo;增删改查&amp;rdquo;有两个层次含义。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第一个层次，是数据访问层次上的。在这个层次上，&amp;ldquo;增删改查&amp;rdquo;只是单纯的数据库操作，&amp;ldquo;增删改查&amp;rdquo;可以理解为&amp;ldquo;插入一条记录，删除一条记录，更新一条记录的信息，获取一条或多条记录&amp;rdquo;四个操作，其意义和着眼点完全是数据访问层面上的，不带有任何业务成分和业务知觉。这个层面上的CRUD应该属于数据访问层的职责。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第二个层次，是业务逻辑层次上的。在这个层次上，&amp;ldquo;增删改查&amp;rdquo;是业务领域内实体的变化以及一系列相关反应，&amp;ldquo;增删改查&amp;rdquo;可以理解为&amp;ldquo;领域内新增一个业务实体，领域内去掉一个业务实体，领域内一个业务实体更新了信息，得到领域内一个或多个业务实体的信息&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 两者最大的不同，是业务层面上的增删改查往往不是单纯的增加减少，还包括实体变化后相关的业务流程。下面举个例子：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;ldquo;添加一个新的订单&amp;rdquo;&amp;mdash;&amp;mdash;这是一条典型的&amp;ldquo;增&amp;rdquo;操作。在数据访问层面上，它的意义是&amp;ldquo;在表示订单的数据表里增加一条记录&amp;rdquo;；而在业务逻辑层面上，它的意义除了&amp;ldquo;领域内多了一个订单实体&amp;rdquo;外，还可能包括&amp;ldquo;根据业务规则判断是否是重复下单，根据金额对下订单客户的等级做相应提升、发送Email和短信通知客户等&amp;rdquo;。可以看到，业务层面上的&amp;ldquo;增&amp;rdquo;可能不仅是简单封装一个简单的插入记录，可能还要去做其他数据访问&amp;mdash;&amp;mdash;提升用户等级，以及做一些非CRUD的业务操作&amp;mdash;&amp;mdash;发送短信通知。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在许多稍微复杂的系统中，业务往往不仅仅是封装了一条数据访问操作，而是还有很多如计算等业务处理，一个业务操作期间可能要多次使用数据访问操作。退一步说，即使某个业务仅仅封装了一条数据访问操作，其意义和层面也是不同的，在数据访问层面，仅仅是多了一条记录，而业务逻辑层面，是领域内多了一个业务实体。也许其本质上都是往数据库插入一条记录，但人类的抽象思维可以将之在不同层面上区分，这也是人类思维层面的一种抽象能力的表现。例如，我们知道太阳升起不过是地球自转使得从背阴面转到了向阳面，但当人们看日出时，很少有人会说&amp;ldquo;看！我们从背阴面转到向阳面了！&amp;rdquo;，我们会说&amp;ldquo;看！日出！&amp;rdquo;，这就是同一事物的不同层次表现。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;2.3.4、存储过程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 也许是性能上的诱惑，许多人喜欢在数据库系统中写很复杂的存储过程。这样，许多业务操作就被写到存储过程中去了。我个人建议，除非对性能要求极高，否则最好还是不要用存储过程实现业务。例如，在一般的系统中，某个业务操作可能需要1秒，而是用了存储过程只用0.1秒，看上去存储过程将效率提高了10倍。但对大多数用户来说，1秒和0.1秒的差别并不大，但是这样做的话，业务会变得十分不容易维护。所以，我个人觉得，除非十分必要，还是不要用存储过程实现业务。&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;a rel=&quot;license&quot; target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot;&gt;&lt;img align=&quot;left&quot; src=&quot;http://i.creativecommons.org/l/by/2.5/cn/88x31.png&quot; alt=&quot;Creative Commons License&quot; style=&quot;border-width: 0px;&quot; /&gt;&lt;/a&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;本文基于&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot; title=&quot;Creative Commons Attribution 2.5 China Mainland License&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;署名 2.5 中国大陆&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;许可协议发布，欢迎转载，演绎或用于商业目的，但是必须保留本文的署名&lt;/span&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;张洋&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;（包含链接）。如您有任何疑问或者授权方面的协商，请&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://space.cnblogs.com/msg/send/leoo2sk&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;给我留言&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;。&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1592568.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 77　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717386/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717386/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717386/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 29 Oct 2009 21:51:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/10/29/1592568.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717386/5313554</fs:itemid></item><item><title>博客园寓言 - 我眼中的博客园现状</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/10/24/1589336.html</link><description>&lt;p&gt;阅读: 3526 评论: 121 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-10-24 23:02 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/24/1589336.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不知从什么时候开始，鄙人发现一向平静祥和的博客园忽然变得波涛汹涌，原本专注于讨论技术的社区，一时间鄙夷声、声讨声、人身攻击声、辱骂声响彻寰宇，不绝于耳。甚至博客园一些元老级和大牛级的人物也开始论战、攻击，无数零贴账户和未注册账户更是嬉笑怒骂，不亦快哉！博客园大有向mop、天涯、cnbeta发展的趋势。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在下不敢说对这些事情的起因了如指掌，但在仔细看过相关帖子、评论后，忽然心血来潮，愿和大家分享一个故事。当然，故事就是故事，也请大家看完后莞尔一笑，继续各忙各。毕竟，大家都是很忙的。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面正式开讲。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;话说有一青年，喜土木建筑，于是考入某大学土木工程系学习土木工程知识，期望能盖出坚固实用美仑轮换的楼房。四年后，学有小成，毕业后进入某建筑公司工作。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 经过N年的磨练，此青年不得大志&amp;mdash;&amp;mdash;没有成为业内著名建筑结构专家或公司首席建筑架构师，但是，不断积累的实践经验也让他在建筑方面颇有些成就。他能轻易建造出二层小楼、别墅等小型建筑，而且经过不断实践，其技术水平越来越高，造的建筑也相当坚固、实用和美观。应该说，如果故事到这里结束，应该很圆满，此青年虽然可能无法成为一代土木工程大师，但应该能成为一个非常优秀的建筑工匠，为人们造出许多实用的别墅和房子。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 但是，过去这些年的经历和实践经验，让这位青年的心态发生了变化，他毅然辞职，开始研究建筑之道，并以&amp;ldquo;做全国最好的别墅和二层小楼&amp;rdquo;为目标，苦学苦练，而其技术也日臻完美。应该说到这里，也还是不错的。不过，在这个时候，他的心态又进一步变化。因为自己长期从事小型建筑的研究和实践，加之其技术确实已经很优秀，且经验丰富，于是他开始质疑起土木工程中一些理论，进而从质疑发展到鄙夷，他鄙夷大学里学的那些微积分、复变函数、解析几何、理论力学、结构力学等理论，因为在他的实践中，这些东西根本没太大作用，有时反而会拖累他。他更开始质疑和鄙视那些满口&amp;ldquo;模式&amp;rdquo;、&amp;ldquo;原则&amp;rdquo;的大师们，觉得那些都是满口空话。越实践，他越坚信自己的正确。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 终于有一天，他爆发了，他要发表自己的看法，发泄自己的不满。于是他开始公开发表并攻击土木工程理论，写出如&amp;ldquo;不懂数学、力学、建筑模式建了10年房子&amp;rdquo;、&amp;ldquo;结构力学离我越来越远去&amp;rdquo;等轰动一时的文章。他发表的文章越来越多，公开表示那些理论、模式的生硬和没用，并用自己的实践经验&amp;mdash;&amp;mdash;那一座座坚固实用的二层小楼作为论据进行证明。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 终于，有些土木学专家和大师看不下去了，开始对这位青年的观点表示自己的不满，并指责其观点会影响新手&amp;mdash;&amp;mdash;特别是那些土木工程专业的新生。这些土木专家天天面对的是摩天大厦和跨江大桥等巨大的项目，日日夜夜地实用各种数学理论和物理理论进行计算和设计，并不断吸取应用各种建筑模式，他们当然知道这些理论的重要性。可是，做惯了二层小楼的青年哪里能体会呢？他坚持着自己的观点，于是，一场青年和专家的论战爆发了。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一方是技艺精湛，实践经验丰富的造房高手；另一方是理论功底扎实，实践经验同样丰富的土木工程专家。于是，双方你来我往，互抛论点、论据，辩论过程异常精彩纷呈，而战况也日趋升级，由辩论发展到指责、再到人身攻击&amp;hellip;&amp;hellip;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这场论战也波及到了其他一些人，其中一批成为青年的fans，也许他们和青年有相同的经历，也许他们被青年优秀的建筑工艺和作品所折服，开始不遗余力挺这个青年。而另一批人则对这个青年张狂的口气和自大的态度十分反感，纷纷对青年加以指责。渐渐的，挺这个青年的占了多数，因为对大多数人来说，会建二层小楼足够用了。而且，青年拿出的一座座精美小作品，也看似比专家拿出的那些枯燥的理论和公式方程有说服力的多。当然，人群中也不乏看热闹的中立者。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 时间在继续，青年依旧陶醉在自己精湛的工艺和近乎完美的二层小楼中，继续表达着他的思想。而专家也有时加以反驳。就这样，青年不能理解理论和模式是如何在建造摩天大厦和跨河大桥时起作用的，专家也依旧鄙视青年的目光短浅和对新人的误导。于是，一切仍在继续&amp;hellip;&amp;hellip;&lt;/span&gt;&lt;/strong&gt;&lt;span style=&quot;color: #000080;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200902/2009022411175028.png&quot; /&gt;作者：&lt;a href=&quot;http://leoo2sk.cnblogs.com/&quot;&gt;&lt;span style=&quot;color: #3399ff;&quot;&gt;T2噬菌体&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;出处：&lt;a href=&quot;http://leoo2sk.cnblogs.com/&quot;&gt;&lt;span style=&quot;color: #3399ff;&quot;&gt;http://leoo2sk.cnblogs.com&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/div&gt;
&lt;/p&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1589336.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 121　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/24/1589336.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/24/1589336.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717706/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/10/24/1589336.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717706/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717706/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 24 Oct 2009 23:02:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/10/24/1589336.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/10/24/1589336.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717706/5313554</fs:itemid></item><item><title>OOA&amp;amp;D实践之路——真实案例解析OO理论与实践（七、【第一轮迭代】需求分析与领域分析）</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/10/23/1588632.html</link><description>&lt;p&gt;阅读: 2551 评论: 24 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-10-23 13:37 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/23/1588632.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #333399;&quot;&gt;查看本系列全部文章：&lt;/span&gt;&lt;br /&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2008/12/12/1353653.html&quot; id=&quot;AjaxHolder_ctl01_TitleUrl&quot; class=&quot;postTitle2&quot;&gt;&lt;span style=&quot;color: #1a8bc8;&quot;&gt;&lt;span style=&quot;color: #00ccff;&quot;&gt;&lt;span style=&quot;color: #33cccc;&quot;&gt;&lt;strong&gt;《OOA&amp;amp;D实践之路&amp;mdash;&amp;mdash;真实案例解析OO理论与实践》索引贴&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在前面，我们花了六篇文章的篇幅去讨论需求分析之前发生的事情，这些内容看起来枯燥或飘渺，但实际是为真正开始系统的分析、设计和实现进行的必要准备。从这篇开始，将正式进入系统的开发阶段。这一篇文章，将讨论第一轮迭代过程中的需求分析和领域分析环节。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;选取第一轮迭代要实现的特性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 回顾前面章节，我们说到，&amp;ldquo;迭代与增量&amp;rdquo;和&amp;ldquo;用例驱动&amp;rdquo;是系统开发的两大法宝。另外，指出了如下几个要点：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）迭代单元不是环节，而是系统功能的某个子集。如不能说第一次迭代完成需求分析、第二次迭代完成设计&amp;hellip;&amp;hellip;这不叫迭代式开发，这叫里程碑式开发，和迭代有本质区别。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）每次迭代一定要完整完成需求分析、系统分析、概要设计、详细设计、编码、测试、部署实施这一套环节，产生的成果必须是成品，是可运行、可交付的，是整个系统的一个子集，而不能是一个半成品。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 所以，说白了，这第一步就是要从前面得到的特性列表或业务用例分析文档中选取一个或几个特性或业务用例进行实现。（因为特性和业务用例有对等映射关系，所以，从特性列表或业务用例分析文档中选取迭代功能点在理论上是等价的。）这里，我们从特性列表选取特性。那么首先把我们前面完成的特性列表再搬出来：&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313422036.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上图就是我们前面得出的特性列表，总共有六个特性。理论上，第一轮选取哪些，总共选取几个，没有明确的规定，但是，在选取特性方面，还是有一定经验可以遵循的，大致有如下原则：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）就选取个数来说，与迭代周期有关。一般的迭代开发中，一个迭代周期大多选在一周到两周之间，不宜多于两周，所以，每个周期选择的特性要估算能在这个周期内完成。（顺便说一下，在每个周期内，如果发现时间不够，做不完计划，应削减一些特性推入下个周期，切不可延长周期。另外，切不可在周期开始后添加任务。）&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）就选取的特性来说，最好是比较内聚的几个特性。也就是说，每个周期选取的特性，要尽量关联紧密，而和其他周期的特性要尽量耦合度低。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）就选取顺序来说，因为要求每一个周期都要产生一个可运行的子集系统，所以，最好先选取平台性、基础性、对外依赖弱的特性，再选取功能性、对外依赖强的特性。例如，在这个例子中，如果第一轮迭代选择特性2则不是一个好主意。因为购物车功能要依赖于管理员、加盟商、物料等诸多特性，在后者没有实现之前，很难单独做出一个可运行的购物车子集系统。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 针对以上原则进行考虑，笔者最终选择3、4和6作为第一轮迭代的特性。&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313423958.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 至于为什么这样选，我就不再分析，请各位结合我上面提到的三个原则自己思考一下。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;领域分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在确定迭代特性后，下一步要进行领域分析。领域分析就是针对特性涉及到的实体及实体间的关系进行一个分析，构造出静态领域模型。这里要注意三点：1、领域模型是静态模型；2、领域模型要反映的是实体及实体见得静态关系（例如包含等，而调用这类动态关系不该在这里出现）；3、领域模型是比较高视角的模型，其中的实体和最终程序中的实体类未必对应。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 领域分析的方法有很多，下面我使用一种我总结的领域分析方法。流程如下：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step1、提取特性中的名词&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我们这个迭代周期内涉及的特性是3、4和6，从中可提取出如下名词：&lt;strong&gt;&lt;span style=&quot;color: #008080;&quot;&gt;加盟商，连锁店，网络，管理员，系统，直属连锁店，原价，等级，折扣&lt;/span&gt;&lt;/strong&gt;。注意，这些名词就是领域实体的候选者。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step2、筛选名词，确定实体&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不是所有候选名词都是领域中的实体，这一步要对候选者进行筛选。这一步非常重要，也相对难度较高，需要结合经验和前面的客户谈论材料、需求记录等，必要时，要咨询客户或业务专家。下面我们进行筛选。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 首先，&amp;ldquo;网络&amp;rdquo;显然不是领域内的实体，排除。&amp;ldquo;系统&amp;rdquo;是对整个产品的总称，也比较明显不是领域实体，排除。排除了两个明显的&amp;ldquo;干扰项&amp;rdquo;，下面看几个可疑的家伙，这里，我发现&amp;ldquo;原价&amp;rdquo;、&amp;ldquo;等级&amp;rdquo;和&amp;ldquo;折扣&amp;rdquo;比较可疑。通过对前面材料的回顾分析，基本可以肯定&amp;ldquo;原价&amp;rdquo;应为物料的一个属性，难以成为单独的实体，排除。而&amp;ldquo;折扣&amp;rdquo;和&amp;ldquo;等级&amp;rdquo;是否能成为实体，依赖于后续系统的设计方式，如果将等级单独设计成一个模块，则其应该为一个实体，而若将其设计为加盟商的属性，则不能成为实体。对于这种摸棱两可的候选项，我们姑且保留，并加一个&amp;ldquo;？&amp;rdquo;作为后缀。当然，由于前面分析中说明&amp;ldquo;折扣关联与等级&amp;rdquo;，所以，仅保留&amp;ldquo;等级&amp;rdquo;就可以了，&amp;ldquo;折扣&amp;rdquo;可作为其属性。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 经过上述筛选，获得下列领域实体：&lt;span style=&quot;color: #008080;&quot;&gt;&lt;strong&gt;加盟商，连锁店，管理员，直属连锁店，等级？&lt;/strong&gt;&lt;/span&gt; 。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我们不妨先将各个实体画入领域分析图。&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313430851.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step3、确定实体间的关系&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 有了实体，下面要确定各个实体间的关系。如上图所示，管理员比较容易确定，因为它似乎不与任何实体存在静态关系。这里比较纠结的是加盟商、连锁店、直属连锁店和等级四个实体。关于它们间的关系我们不能臆想，要去查阅前面的记录资料或去咨询客户。在&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2008/12/11/1352021.html&quot;&gt;&lt;span style=&quot;color: #669966;&quot;&gt;OOA&amp;amp;D实践之路&amp;mdash;&amp;mdash;真实案例解析OO理论与实践（三、降低风险）&lt;/span&gt;&lt;/a&gt;一文中，我们记录了这样一段文字：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;em&gt;&amp;ldquo;加盟商和连锁店不是一个概念，加盟商直属总公司，连锁店可能直属总公司也可能直属某加盟商。加盟商和直属总公司的连锁店直接向总公司定料，不直属的的连锁店向相应加盟商领取原料。连锁店按原价定料，加盟商按照等级分为5级，每级折扣不同。&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 从以上文字中，我们提炼出如下关系：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）加盟商和连锁店没有关系。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）直属连锁店是连锁店的一种特例。而且应该还有种&amp;ldquo;非直属连锁店&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3）非直属连锁店可能会属于某个加盟商。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4）等级仅属于加盟商。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 到这里为止，几个实体间的关系基本清晰了，我们将其表达在领域分析图里：&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313432581.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 以上就是第一轮迭代的领域分析图了。其中直属连锁店和非直属连锁店都继承于连锁店，而非直属连锁店必定对应一个加盟商，加盟商可以对应零到多个非直属连锁店，每个加盟商有且只有一个对应的等级。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step4、领域分析的优化&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 别觉得完成上述步骤就万事大吉了，虽然我们的领域分析模型已经出来了，但它可靠吗？还有优化的余地吗？万事多思考一点，总是没坏处的。就像刚出厂没经过检测的飞机，你敢坐吗？所以，这里我们要对已经成型的领域分析模型进行一个检测。检测的方法很简单，就是回顾前述工作，逐个点进行验证和确认。当我回顾了特性及初步业务需求后，发现如下两点问题：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第一、管理员是否是领域中的实体？要知道，领域中的实体，一定是系统边界内的实体。那这里就要分情况讨论了，如果系统只需要一个管理员，那么系统中就没有对管理员的管理，那么管理员只是系统外部的用户，就不能存在于领域实体中了；如果有多个管理员，并且管理员管理单独成为一个模块，则管理员应放在这里。于是我联系了客户，在确认系统只需要一个管理员后，我毫不犹豫将管理员从领域模型中抹去了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 第二、我觉得领域模型抽象层次还有所欠缺。加盟商和连锁店性质很类似，都有注册、都要被审核，其实它们应该继承自某个更高抽象，这里我称其为会员。于是经过思考和修正，得到最终的领域模型如下：&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313434256.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;这里要注意，领域模型只表示出实体和实体间的静态关系就好了。至于各个实体有哪些属性，有哪些交互，那是后面设计阶段的工作。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;基于用例的需求分析&amp;mdash;&amp;mdash;编写用例图及用例规约&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 传统的软件工程中，通常使用需求规格说明书进行系统需求分析。而我更喜欢使用用例分析技术。在用例分析阶段，我们要输出两份文档：用例图和用例规约。用例图用于概观上描述需求，用例规约用于对用例的流程进行详细描述，直接作为后续设计、编码及测试的依据。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面进行系统需求分析。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step1、提取特性中的动词&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 上面我们曾使用提取名词法找实体，那么要找用例，就要分析特性中的动词了。废话不多说，我们先提取出特性3、4和6中的动词：&lt;span style=&quot;color: #008080;&quot;&gt;&lt;strong&gt;注册，审核，使用，管理，定料&lt;/strong&gt;&lt;/span&gt;。因为用例分析中要确定每个用例的Actor，所以，在提取完动词后，要对每个动词赋予其主语，作为其Actor，于是，最终得到的提取列表如下：&lt;span style=&quot;color: #008080;&quot;&gt;&lt;strong&gt;注册【未注册加盟商和连锁店】，审核【管理员】，使用【注册后的加盟商和连锁店】，管理【管理员】，定料【注册后的加盟商和连锁店】&lt;/strong&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step2、动词筛选&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 同样的，不是每个动词都是合法的用例，这里也要对候选动词进行筛选。具体到这里，&amp;ldquo;使用&amp;rdquo;是个很泛的名词，不应该成为用例，而&amp;ldquo;定料&amp;rdquo;虽是用例，但于这轮迭代的内聚性不高，建议放入后续迭代中。最后得到用例：&lt;strong&gt;&lt;span style=&quot;color: #008080;&quot;&gt;注册【未注册加盟商和连锁店】，审核【管理员】，管理【管理员】&lt;/span&gt; &lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step3、用例分析与优化&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里的用例有进一步分析的余地，首先，&amp;ldquo;管理&amp;rdquo;这个用例粒度太大，很难知道设计和开发，于是应进行分解；其次，&amp;ldquo;审核&amp;rdquo;应属于管理的一部分。基于以上两点，将管理分解为&amp;ldquo;删除会员&amp;rdquo;、&amp;ldquo;指定加盟商等级&amp;rdquo;和&amp;ldquo;审核会员&amp;rdquo;，另外，&amp;ldquo;未注册的加盟商和连锁店&amp;rdquo;，跟据领域分析，可写作&amp;ldquo;未注册会员&amp;rdquo;。另外，这里有几个隐含的用例，就是关于等级的管理，这几个用例从动词分析中是提取不出来了，这取决于特性描述的局限性。我们通过经验和个人的分析，得到关于等级的管理用例。于是，最终用例敲定如下（这里用例命名规则为 uc迭代周期编号.用例编号）：&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uc1.1 - 注册 actor：未注册会员&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uc1.2 - 删除会员 actor：管理员&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uc1.3 - 指定加盟商等级 actor：管理员&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uc1.4 - 审核会员 actor：管理员&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uc1.5 - 添加等级 actor：管理员&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uc1.6 - 删除等级 actor：管理员&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uc1.7 - 等级信息维护 actor：管理员&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step4、给出用例图&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 跟据上述分析，给出用例图如下：&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313440261.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #004080;&quot;&gt;step4、编写用例规约&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 需求分析的最后一步，就是为每个用例编写相应的用例规约。用例规约是一种规范化文档，它面向设计开发人员，详细描述了各个用例内部的基本信息、执行流程及例外流程等，必要时可附上相应的活动图。因为用例规约是设计和开发的重要参考文档，所以在编写过程中务必要做到详尽和准确。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面仅给出&amp;ldquo;注册&amp;rdquo;这个用例的用例规约作为示例和参考。&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313445444.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 必要时，可在下端附上活动图：&lt;/p&gt;
&lt;p style=&quot;TEXT-ALIGN: center&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200910/2009102313451636.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在每个迭代周期的初始阶段，当选择完需要迭代的特性后，就可以开始领域分析和需求分析了。本文是先进行领域分析。其实两者并无确定的先后顺序，往往是相辅相成，交叉进行。下一篇文章将进入第一迭代周期的设计阶段。&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200902/2009022411175028.png&quot; /&gt;作者：&lt;a href=&quot;http://leoo2sk.cnblogs.com/&quot;&gt;&lt;span style=&quot;color: #3399ff;&quot;&gt;T2噬菌体&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;出处：&lt;a href=&quot;http://leoo2sk.cnblogs.com/&quot;&gt;&lt;span style=&quot;color: #3399ff;&quot;&gt;http://leoo2sk.cnblogs.com&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1588632.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 24　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/23/1588632.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/23/1588632.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717818/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/10/23/1588632.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717818/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717818/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 23 Oct 2009 13:37:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/10/23/1588632.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/10/23/1588632.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717818/5313554</fs:itemid></item><item><title>最近的生活及一些感悟</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/10/16/1584792.html</link><description>&lt;p&gt;阅读: 1159 评论: 24 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-10-16 22:20 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/16/1584792.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 今天打开博客园看了看，发现自己的最后一篇帖子是6月17日发的。仔细想想，真是很久没有写博客了。这四个月很忙，也经历了很多事情，所以想写篇博文和大家聊聊。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关于最近忙活的事情&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6月中旬开始，主要的事情就是忙着学期末的课程考试和考核。因为学分已经选够，所以，研一下学期的这几门课，应该是我人生中最后一次期末课程考核了。由于平时的懈怠，备考期间比较紧张，还好抓紧了最后的时间，几门课都有惊无险的过了。想想从小学，到初中、高中，再到大学，到研究生，这17年求学生涯上了不下几千节课了吧，现在，&amp;ldquo;上课&amp;rdquo;这个词在我的人生中永远消失了，还真有些伤感。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在征得导师同意后，7月初我带着一纸offer和一个旅行箱，坐上了前往深圳的飞机，来到了T公司，开始了为期三个月的实习。第一次来到南方，来到一个陌生的城市，刚开始真有些不习惯。还好T公司对我们的照顾比较周到，给提供了半个月的四星级酒店住宿，让我有时间缓冲。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在T公司实习的三个月，过得很充实，虽然工作很忙，但做起事情来很快乐，看来我就是天生写程序的命了。期间去了两趟香港，第一次是和同事一起去看香港动漫节，第二次自己去的，去了旺角、尖沙咀和海港城，给父母、朋友和同学买了些礼物。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 实习的日子过得很快，9月30号辞职，办了离职手续，10月2号经上海转机回到家里，见到了半年没见的父母，很开心。和父母过了个中秋节，然后在家幸福的呆了十天，飞回了北京。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 回了北京，最紧要的就是和导师聊了开题的事，大约有了方向，目前正在大量阅读相关论文及资料。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 虽然深圳消费很高，不过T公司的待遇不错，实习过后，手里还是剩余了不错的可供支配的收入。于是几天前，拿出一部分钱买了人生中第一个笔记本电脑，实现了我N年前的誓言：第一个本要自己挣钱买。用着用自己的收入买的笔记本，很有成就感。算了算，剩下的钱大约够我这个学期的生活费了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面的日子，就主要忙我的毕业开题了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关于实习&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这次实习去的T公司，是国内比较知名的一家互联网公司。我的职位是Web及Web前端开发，主要负责一个SNS社区产品的特性开发及性能优化，用到的技术主要是PHP和JavaScript。在T公司的三个月，对我的冲击比较大，让我觉得自己真的是井底之蛙。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最主要的感悟，是自己是在太菜了。我所在的组，并不是公司里大牛聚集的组，但组内随便抓出一个人，其技术水平都让我望尘莫及，偶尔接触过别的组的大牛，其水平之高深莫测让我简直无法想象。他们所学、所想、所做的事、所讨论的问题和我平时所思考所讨论的东西简直不在一个级别上。打个比喻，就像他们讨论的是微分方程，而我天天思考的还是四则运算法则。在这种环境中，除了做好份内工作，就是多多向他们学习，感觉三个月，学到了不少东西。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 通过实习，第一次真正见识了大企业大团队规范化的软件开发过程及项目管理。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 另外，T公司的产品用户量惊人，我所在团队开发的SNS产品日PV数以亿计，我做的每一个特性，每天都可能被几十万、几百万次点击使用，做这种东西和自己在实验室写YY的代码完全不同，无时无刻都要考虑代码的安全性和效率。例如，又一次，我做的一个逻辑server上线后，拖垮了好几台服务器，哪几台负责跑server的机子负载全部超过7，经过排查，发现是我一个SQL语句子查询写得不合理，经过简单的优化，马上负载降低到零点几，一个小小的改动，负载出现数千倍差距。这种情况只有在请求密度巨大的情况下才会出现，如果是YY的东西，完全不会发现这种问题。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 还有一次，我调试时注释掉了两行代码，提测时忘记去掉注释符号，结果测试的同事也没测试出来，那个版本发布后，导致中学无法注册，结果当天运维监测中学注册数暴降，造成了一次不小的事故。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 三个月的实习，让我对很多东西的态度产生了变化，对技术的很多东西，都要重新思考。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关于毕业设计&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 接下来的一年，都要集中精力做毕业设计。前段时间和导师沟通，只是确定了大体的方向，具体的开题点没有找到，因为根据学校规定，研究生要毕业，一定要求创新性的理论。最近不断看资料，但还没有灵感。感觉从外面回来，还没有进入学习的状态，每天很浮躁，希望能尽快找到学习的感觉吧。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关于博客园&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 很久没有更新自己的博客，确实是有点懒了，而且，也想不到有什么东西可以和大家分享。等一有想法，一定会更新自己的博客，和大家分享讨论技术是我最开始的事情之一。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 虽然没有更新自己的博客，不过还是经常会到博客园看看。最近博客园貌似很热闹，具体我也不多说了，还是希望各位对事情淡然一点，谦逊一点。有问题心平气和讨论。希望博客园越来越好。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;img src=&quot;http://pic002.cnblogs.com/img/leoo2sk/200902/2009022411175028.png&quot; /&gt;作者：&lt;a href=&quot;http://leoo2sk.cnblogs.com/&quot;&gt;&lt;span style=&quot;color: #3399ff;&quot;&gt;T2噬菌体&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;出处：&lt;a href=&quot;http://leoo2sk.cnblogs.com/&quot;&gt;&lt;span style=&quot;color: #3399ff;&quot;&gt;http://leoo2sk.cnblogs.com&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/div&gt;
&lt;/blockquote&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1584792.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 24　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/16/1584792.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/10/16/1584792.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717820/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/10/16/1584792.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717820/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717820/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 16 Oct 2009 22:20:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/10/16/1584792.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/10/16/1584792.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717820/5313554</fs:itemid></item><item><title>依赖注入那些事儿</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html</link><description>&lt;p&gt;阅读: 7552 评论: 111 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-06-17 00:26 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;写在前面的话&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;昨天在博客园上看到一篇博文，名为&amp;ldquo;什么是依赖注入？（来听一个笑话）&amp;rdquo;[&lt;/span&gt;&lt;/em&gt;&lt;a href=&quot;http://www.cnblogs.com/imbob/archive/2009/06/12/1502119.html&quot;&gt;&lt;em&gt;点击这里访问&lt;/em&gt;&lt;/a&gt;&lt;em&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;]。可以看出，作者是想以一种轻松幽默的方式对依赖注入的思想进行一个阐述。不过在读完文章后，个人觉得文章过于浅薄，没有真正将依赖注入的思想解释清楚，也没有深入的分析和具体的示例，所用比喻也有点低俗（至少笔者读完文章后觉得胃里不是很舒服）。&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;但是，这篇博文启发了我。回想自己平常的学习和工作，依赖注入确实是软件架构和开发中一个十分重要的概念和技术，笔者参与的几乎每一个项目都用到了它，并且得到了很好的效果。于是，笔者萌发了写这篇文章的想法，意在将依赖注入这项概念本身结合笔者的实践经验及所感所想，做一个相对完整的综述，并总结于此文。一来可以和朋友们分享这项技术及个人心得，二来也是自己对这项技术做的一个总结。&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;目录&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;写在前面的话&lt;/p&gt;
&lt;p&gt;目录&lt;/p&gt;
&lt;p&gt;1 IGame游戏公司的故事&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.1 讨论会&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.2 实习生小李的实现方法&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.3 架构师的建议&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.4 小李的小结&lt;/p&gt;
&lt;p&gt;2 探究依赖注入&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.1 故事的启迪&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.2 正式定义依赖注入&lt;/p&gt;
&lt;p&gt;3 依赖注入那些事儿&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.1 依赖注入的类别&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.1.1 Setter注入&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.1.2 Construtor注入&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.1.3 依赖获取&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.2 反射与依赖注入&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.3 多态的活性与依赖注入&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.3.1 多态性的活性&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3.3.2 不同活性多态性依赖注入的选择&lt;/p&gt;
&lt;p&gt;4 IoC Container&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.1 IoC Container出现的必然性&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.2 IoC Container的分类&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.2.1 重量级IoC Container&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.2.2 轻量级IoC Container&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.3 .NET平台上典型IoC Container推介&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.3.1 Spring.NET&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.3.2 Unity&lt;/p&gt;
&lt;p&gt;参考文献&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;1 IGame游戏公司的故事&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.1 讨论会&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;话说有一个叫IGame的游戏公司，正在开发一款ARPG游戏（动作&amp;amp;角色扮演类游戏，如魔兽世界、梦幻西游这一类的游戏）。一般这类游戏都有一个基本的功能，就是打怪（玩家攻击怪物，借此获得经验、虚拟货币和虚拟装备），并且根据玩家角色所装备的武器不同，攻击效果也不同。这天，IGame公司的开发小组正在开会对打怪功能中的某一个功能点如何实现进行讨论，他们面前的大屏幕上是这样一份需求描述的ppt：&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;504&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/01_3.gif&quot; height=&quot;379&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图1.1 需求描述ppt&lt;/p&gt;
&lt;p&gt;各个开发人员，面对这份需求，展开了热烈的讨论，下面我们看看讨论会上都发生了什么。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.2 实习生小李的实现方式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在经过一番讨论后，项目组长Peter觉得有必要整理一下各方的意见，他首先询问小李的看法。小李是某学校计算机系大三学生，对游戏开发特别感兴趣，目前是IGame公司的一名实习生。&lt;/p&gt;
&lt;p&gt;经过短暂的思考，小李阐述了自己的意见：&lt;/p&gt;
&lt;p&gt;&amp;ldquo;我认为，这个需求可以这么实现。HP当然是怪物的一个属性成员，而武器是角色的一个属性成员，类型可以使字符串，用于描述目前角色所装备的武器。角色类有一个攻击方法，以被攻击怪物为参数，当实施一次攻击时，攻击方法被调用，而这个方法首先判断当前角色装备了什么武器，然后据此对被攻击怪物的HP进行操作，以产生不同效果。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;而在阐述完后，小李也飞快的在自己的电脑上写了一个Demo，来演示他的想法，Demo代码如下。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：怪物&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLi&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// 怪物&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Monster&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 怪物的名字&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String Name { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 怪物的生命值&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; Int32 HP { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; Monster(String name,Int32 hp)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Name = name;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.HP = hp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  28:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  29:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：角色&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLi&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// 角色&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Role&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; Random _random = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Random();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 表示角色目前所持武器的字符串&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String WeaponTag { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 攻击怪物&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;param name=&quot;monster&quot;&amp;gt;被攻击的怪物&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Attack(Monster monster)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (monster.HP &amp;lt;= 0)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  28:&lt;/span&gt;                 Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;此怪物已死&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  29:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  30:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  31:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  32:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #006080;&quot;&gt;&quot;WoodSword&quot;&lt;/span&gt; == &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.WeaponTag)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  33:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  34:&lt;/span&gt;                 monster.HP -= 20;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  35:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (monster.HP &amp;lt;= 0)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  36:&lt;/span&gt;                 {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  37:&lt;/span&gt;                     Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;攻击成功！怪物&quot;&lt;/span&gt; + monster.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;已死亡&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  38:&lt;/span&gt;                 }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  39:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  40:&lt;/span&gt;                 {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  41:&lt;/span&gt;                     Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;攻击成功！怪物&quot;&lt;/span&gt; + monster.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;损失20HP&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  42:&lt;/span&gt;                 }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  43:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  44:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #006080;&quot;&gt;&quot;IronSword&quot;&lt;/span&gt; == &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.WeaponTag)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  45:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  46:&lt;/span&gt;                 monster.HP -= 50;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  47:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (monster.HP &amp;lt;= 0)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  48:&lt;/span&gt;                 {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  49:&lt;/span&gt;                     Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;攻击成功！怪物&quot;&lt;/span&gt; + monster.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;已死亡&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  50:&lt;/span&gt;                 }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  51:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  52:&lt;/span&gt;                 {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  53:&lt;/span&gt;                     Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;攻击成功！怪物&quot;&lt;/span&gt; + monster.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;损失50HP&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  54:&lt;/span&gt;                 }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  55:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  56:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #006080;&quot;&gt;&quot;MagicSword&quot;&lt;/span&gt; == &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.WeaponTag)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  57:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  58:&lt;/span&gt;                 Int32 loss = (_random.NextDouble() &amp;lt; 0.5) ? 100 : 200;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  59:&lt;/span&gt;                 monster.HP -= loss;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  60:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (200 == loss)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  61:&lt;/span&gt;                 {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  62:&lt;/span&gt;                     Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;出现暴击！！！&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  63:&lt;/span&gt;                 }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  64:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  65:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (monster.HP &amp;lt;= 0)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  66:&lt;/span&gt;                 {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  67:&lt;/span&gt;                     Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;攻击成功！怪物&quot;&lt;/span&gt; + monster.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;已死亡&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  68:&lt;/span&gt;                 }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  69:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  70:&lt;/span&gt;                 {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  71:&lt;/span&gt;                     Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;攻击成功！怪物&quot;&lt;/span&gt; + monster.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;损失&quot;&lt;/span&gt; + loss + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;HP&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  72:&lt;/span&gt;                 }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  73:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  74:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  75:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  76:&lt;/span&gt;                 Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;角色手里没有武器，无法攻击！&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  77:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  78:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  79:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  80:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：测试代码&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLi&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Program&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Main(&lt;span style=&quot;color: #0000ff;&quot;&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//生成怪物&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;             Monster monster1 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;小怪A&quot;&lt;/span&gt;, 50);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             Monster monster2 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;小怪B&quot;&lt;/span&gt;, 50);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;             Monster monster3 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;关主&quot;&lt;/span&gt;, 200);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;             Monster monster4 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;最终Boss&quot;&lt;/span&gt;, 1000);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//生成角色&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             Role role = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Role();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//木剑攻击&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;             role.WeaponTag = &lt;span style=&quot;color: #006080;&quot;&gt;&quot;WoodSword&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;             role.Attack(monster1);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//铁剑攻击&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;             role.WeaponTag = &lt;span style=&quot;color: #006080;&quot;&gt;&quot;IronSword&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt;             role.Attack(monster2);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  28:&lt;/span&gt;             role.Attack(monster3);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  29:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  30:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//魔剑攻击&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  31:&lt;/span&gt;             role.WeaponTag = &lt;span style=&quot;color: #006080;&quot;&gt;&quot;MagicSword&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  32:&lt;/span&gt;             role.Attack(monster3);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  33:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  34:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  35:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  36:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  37:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  38:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  39:&lt;/span&gt;             Console.ReadLine();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  40:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  41:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  42:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;程序运行结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;289&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/02_3.gif&quot; height=&quot;226&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图1.2 小李程序的运行结果&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.3 架构师的建议&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;小李阐述完自己的想法并演示了Demo后，项目组长Peter首先肯定了小李的思考能力、编程能力以及初步的面向对象分析与设计的思想，并承认小李的程序正确完成了需求中的功能。但同时，Peter也指出小李的设计存在一些问题，他请小于讲一下自己的看法。&lt;/p&gt;
&lt;p&gt;小于是一名有五年软件架构经验的架构师，对软件架构、设计模式和面向对象思想有较深入的认识。他向Peter点了点头，发表了自己的看法：&lt;/p&gt;
&lt;p&gt;&amp;ldquo;小李的思考能力是不错的，有着基本的面向对象分析设计能力，并且程序正确完成了所需要的功能。不过，这里我想从架构角度，简要说一下我认为这个设计中存在的问题。&lt;/p&gt;
&lt;p&gt;首先，小李设计的Role类的Attack&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;方法很长&lt;/strong&gt;&lt;/span&gt;，并且方法中有一个&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;冗长的if&amp;hellip;else结构&lt;/strong&gt;&lt;/span&gt;，且&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;每个分支的代码的业务逻辑很相似，只是很少的地方不同&lt;/strong&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;再者，我认为这个设计比较大的一个问题是，&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;违反了OCP原则&lt;/strong&gt;&lt;/span&gt;。在这个设计中，如果以后我们增加一个新的武器，如倚天剑，每次攻击损失500HP，那么，我们就要打开Role，修改Attack方法。而&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;我们的代码应该是对修改关闭的，当有新武器加入的时候，应该使用扩展完成，避免修改已有代码&lt;/strong&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;一般来说，&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;当一个方法里面出现冗长的if&amp;hellip;else或switch&amp;hellip;case结构，且每个分支代码业务相似时，往往预示这里应该引入多态性来解决问题&lt;/strong&gt;&lt;/span&gt;。而这里，如果把不同武器攻击看成一个策略，那么引入策略模式（Strategy Pattern）是明智的选择。&lt;/p&gt;
&lt;p&gt;最后说一个小的问题，被攻击后，减&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;HP、死亡判断等都是怪物的职责&lt;/strong&gt;&lt;/span&gt;，这里放在Role中有些不当。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8040;&quot;&gt;&lt;em&gt;Tip：OCP原则，即开放关闭原则，指设计应该对扩展开放，对修改关闭。&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8040;&quot;&gt;&lt;em&gt;Tip：策略模式，英文名Strategy Pattern，指定义算法族，分别封装起来，让他们之间可以相互替换，此模式使得算法的变化独立于客户。&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;小于边说，边画了一幅UML类图，用于直观表示他的思想。&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;586&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/03_3.jpg&quot; height=&quot;407&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图1.3 小于的设计&lt;/p&gt;
&lt;p&gt;Peter让小李按照小于的设计重构Demo，小李看了看小于的设计图，很快完成。相关代码如下：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：IAttackStrategy接口&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLiAdv&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;interface&lt;/span&gt; IAttackStrategy&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; AttackTarget(Monster monster);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：木剑&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLiAdv&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; WoodSword : IAttackStrategy&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; AttackTarget(Monster monster)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             monster.Notify(20);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：铁剑&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLiAdv&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; IronSword : IAttackStrategy&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; AttackTarget(Monster monster)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             monster.Notify(50);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：魔剑&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLiAdv&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; MagicSword : IAttackStrategy&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; Random _random = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Random();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; AttackTarget(Monster monster)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             Int32 loss = (_random.NextDouble() &amp;lt; 0.5) ? 100 : 200;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (200 == loss)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;                 Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;出现暴击！！！&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             monster.Notify(loss);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：怪物&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLiAdv&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// 怪物&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Monster&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 怪物的名字&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String Name { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 怪物的生命值&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; Int32 HP { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; Monster(String name,Int32 hp)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Name = name;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.HP = hp;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  28:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  29:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  30:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 怪物被攻击时，被调用的方法，用来处理被攻击后的状态更改&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  31:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  32:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;param name=&quot;loss&quot;&amp;gt;此次攻击损失的HP&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  33:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Notify(Int32 loss)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  34:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  35:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.HP &amp;lt;= 0)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  36:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  37:&lt;/span&gt;                 Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;此怪物已死&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  38:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  39:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  40:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  41:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.HP -= loss;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  42:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.HP &amp;lt;= 0)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  43:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  44:&lt;/span&gt;                 Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;怪物&quot;&lt;/span&gt; + &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;被打死&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  45:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  46:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  47:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  48:&lt;/span&gt;                 Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;怪物&quot;&lt;/span&gt; + &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Name + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;损失&quot;&lt;/span&gt; + loss + &lt;span style=&quot;color: #006080;&quot;&gt;&quot;HP&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  49:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  50:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  51:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  52:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：角色&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLiAdv&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// 角色&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;     &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Role&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 表示角色目前所持武器&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; IAttackStrategy Weapon { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// 攻击怪物&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;         &lt;span style=&quot;color: #008000;&quot;&gt;/// &amp;lt;param name=&quot;monster&quot;&amp;gt;被攻击的怪物&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Attack(Monster monster)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Weapon.AttackTarget(monster);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：测试代码&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; IGameLiAdv&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Program&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Main(&lt;span style=&quot;color: #0000ff;&quot;&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//生成怪物&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;             Monster monster1 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;小怪A&quot;&lt;/span&gt;, 50);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             Monster monster2 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;小怪B&quot;&lt;/span&gt;, 50);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;             Monster monster3 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;关主&quot;&lt;/span&gt;, 200);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;             Monster monster4 = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Monster(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;最终Boss&quot;&lt;/span&gt;, 1000);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//生成角色&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             Role role = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Role();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//木剑攻击&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;             role.Weapon = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; WoodSword();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;             role.Attack(monster1);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//铁剑攻击&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;             role.Weapon = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; IronSword();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt;             role.Attack(monster2);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  28:&lt;/span&gt;             role.Attack(monster3);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  29:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  30:&lt;/span&gt;             &lt;span style=&quot;color: #008000;&quot;&gt;//魔剑攻击&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  31:&lt;/span&gt;             role.Weapon = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; MagicSword();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  32:&lt;/span&gt;             role.Attack(monster3);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  33:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  34:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  35:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  36:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  37:&lt;/span&gt;             role.Attack(monster4);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  38:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  39:&lt;/span&gt;             Console.ReadLine();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  40:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  41:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  42:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;编译运行以上代码，得到的运行结果与上一版本代码基本一致。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.4 小李的小结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Peter显然对改进后的代码比较满意，他让小李对照两份设计和代码，进行一个小结。小李简略思考了一下，并结合小于对一次设计指出的不足，说道：&lt;/p&gt;
&lt;p&gt;&amp;ldquo;我认为，改进后的代码有如下优点：&lt;/p&gt;
&lt;p&gt;第一，虽然类的数量增加了，但是每个类中方法的代码都非常短，没有了以前Attack方法那种很长的方法，也没有了冗长的if&amp;hellip;else，&lt;strong&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;代码结构变得很清晰&lt;/span&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;第二，&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;类的职责更明确了&lt;/strong&gt;&lt;/span&gt;。在第一个设计中，Role不但负责攻击，还负责给怪物减少HP和判断怪物是否已死。这明显不应该是Role的职责，改进后的代码将这两个职责移入Monster内，使得职责明确，提高了类的内聚性。&lt;/p&gt;
&lt;p&gt;第三，引入Strategy模式后，不但&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;消除了重复性代码&lt;/strong&gt;&lt;/span&gt;，更重要的是，&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;使得设计符合了OCP&lt;/strong&gt;&lt;/span&gt;。如果以后要加一个新武器，只要新建一个类，实现IAttackStrategy接口，当角色需要装备这个新武器时，客户代码只要实例化一个新武器类，并赋给Role的Weapon成员就可以了，已有的Role和Monster代码都不用改动。这样就实现了对扩展开发，对修改关闭。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Peter和小于听后都很满意，认为小李总结的非常出色。&lt;/p&gt;
&lt;p&gt;IGame公司的讨论会还在进行着，内容是非常精彩，不过我们先听到这里，因为，接下来，我们要对其中某些问题进行一点探讨。别忘了，本文的主题可是依赖注入，这个主角还没登场呢！让主角等太久可不好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;2 探究依赖注入&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.1 故事的启迪&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们现在静下心来，再回味一下刚才的故事。因为，这个故事里面隐藏着依赖注入的出现原因。我说过不只一次，&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;想真正认清一个事物，不能只看&amp;ldquo;它是什么？什么样子？&amp;rdquo;，而应该先弄清楚&amp;ldquo;它是怎么来的？是什么样的需求和背景促使了它的诞生？它被创造出来是做什么用的？&amp;rdquo;。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;回想上面的故事。刚开始，主要需求是一个打怪的功能。小李做了一个初步面向对象的设计：抽取领域场景中的实体（怪物、角色等），封装成类，并为各个类赋予属性与方法，最后通过类的交互完成打怪功能，这应该算是面向对象设计的初级阶段。&lt;/p&gt;
&lt;p&gt;在小李的设计基础上，架构师小于指出了几点不足，如不符合OCP，职责划分不明确等等，并根据情况引入策略模式。这是更高层次的面向对象设计。其实就核心来说，小于只做了一件事：&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;利用多态性，隔离变化&lt;/strong&gt;&lt;/span&gt;。它清楚认识到，这个打怪功能中，有些业务逻辑是不变的，如角色攻击怪物，怪物减少HP，减到0怪物就会死；而变化的仅仅是不同的角色持有不同武器时，每次攻击的效用不一样。于是他的架构，本质就是把变化的部分和不变的部分隔离开，使得变化部分发生变化时，不变部分不受影响。&lt;/p&gt;
&lt;p&gt;我们再仔细看看小于的设计图，这样设计后，有个基本的问题需要解决：现在Role不依赖具体武器，而仅仅依赖一个IAttackStrategy接口，接口是不能实例化的，虽然Role的Weapon成员类型定义为IAttackStrategy，但最终还是会被赋予一个实现了IAttackStrategy接口的具体武器，并且随着程序进展，一个角色会装备不同的武器，从而产生不同的效用。赋予武器的职责，在Demo中是放在了测试代码里。&lt;/p&gt;
&lt;p&gt;这里，测试代码实例化一个具体的武器，并赋给Role的Weapon成员的过程，就是依赖注入！这里要清楚，依赖注入其实是一个过程的称谓！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.2 正式定义依赖注入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下面，用稍微正式一点的语言，定义依赖注入产生的背景缘由和依赖注入的含义。在读的过程中，读者可以结合上面的例子进行理解。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;依赖注入产生的背景：&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;随着面向对象分析与设计的发展，一个良好的设计，核心原则之一就是将变化隔离，使得变化部分发生变化时，不变部分不受影响（这也是OCP的目的）。为了做到这一点，要利用面向对象中的多态性，使用多态性后，客户类不再直接依赖服务类，而是依赖于一个抽象的接口，这样，客户类就不能在内部直接实例化具体的服务类。但是，客户类在运作中又客观需要具体的服务类提供服务，因为接口是不能实例化去提供服务的。就产生了&amp;ldquo;客户类不准实例化具体服务类&amp;rdquo;和&amp;ldquo;客户类需要具体服务类&amp;rdquo;这样一对矛盾。为了解决这个矛盾，开发人员提出了一种模式：&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;客户类（如上例中的Role）&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;定义一个&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;注入点（Public成员Weapon），&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;用于&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;服务类（实现IAttackStrategy的具体类，如WoodSword、IronSword和MagicSword，也包括以后加进来的所有实现IAttackStrategy的新类）&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;的注入，而&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;客户类的客户类（Program，即测试代码）&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;负责根据情况，实例化服务类，注入到客户类中，从而解决了这个矛盾。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;依赖注入的正式定义：&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;strong&gt;依赖注入（Dependency Injection），是这样一个过程：由于某客户类只依赖于服务类的一个接口，而不依赖于具体服务类，所以客户类只定义一个注入点。在程序运行过程中，客户类不直接实例化具体服务类实例，而是客户类的运行上下文环境或专门组件负责实例化服务类，然后将其注入到客户类中，保证客户类的正常运行。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;3 依赖注入那些事儿&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;上面我们从需求背景的角度，讲述了依赖注入的来源和定义。但是，如果依赖注入仅仅就只有这么点东西，那也没有什么值得讨论的了。但是，上面讨论的仅仅是依赖注入的内涵，其外延还是非常广泛的，从依赖注入衍生出了很多相关的概念与技术，下面我们讨论一下依赖注入的&amp;ldquo;那些事儿&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1 依赖注入的类别&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;依赖注入有很多种方法，上面看到的例子中，只是其中的一种，下面分别讨论不同的依赖注入类型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1.1 Setter注入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第一种依赖注入的方式，就是Setter注入，上面的例子中，将武器注入Role就是Setter注入。正式点说：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;strong&gt;Setter注入（Setter Injection）是指在客户类中，设置一个服务类接口类型的数据成员，并设置一个Set方法作为注入点，这个Set方法接受一个具体的服务类实例为参数，并将它赋给服务类接口类型的数据成员。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;566&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/04_6.jpg&quot; height=&quot;352&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图3.1 Setter注入示意&lt;/p&gt;
&lt;p&gt;上图展示了Setter注入的结构示意图，客户类ClientClass设置IServiceClass类型成员_serviceImpl，并设置Set_ServiceImpl方法作为注入点。Context会负责实例化一个具体的ServiceClass，然后注入到ClientClass里。&lt;/p&gt;
&lt;p&gt;下面给出Setter注入的示例代码。&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：IServiceClass&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; SetterInjection&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;interface&lt;/span&gt; IServiceClass&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         String ServiceInfo();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：ServiceClassA&lt;/span&gt; &lt;/div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; SetterInjection&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; ServiceClassA : IServiceClass&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String ServiceInfo()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #006080;&quot;&gt;&quot;我是ServceClassA&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：ServiceClassB&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; SetterInjection&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; ServiceClassB : IServiceClass&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String ServiceInfo()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #006080;&quot;&gt;&quot;我是ServceClassB&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：ClientClass&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; SetterInjection&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; ClientClass&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; IServiceClass _serviceImpl;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Set_ServiceImpl(IServiceClass serviceImpl)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;._serviceImpl = serviceImpl;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; ShowInfo()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             Console.WriteLine(_serviceImpl.ServiceInfo());&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：Context&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; SetterInjection&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Program&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Main(&lt;span style=&quot;color: #0000ff;&quot;&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             IServiceClass serviceA = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; ServiceClassA();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;             IServiceClass serviceB = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; ServiceClassB();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             ClientClass client = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; ClientClass();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;             client.Set_ServiceImpl(serviceA);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;             client.ShowInfo();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;             client.Set_ServiceImpl(serviceB);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             client.ShowInfo();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;运行结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;184&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/05_3.jpg&quot; height=&quot;104&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图3.2 Setter注入运行结果&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1.2 构造注入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;另外一种依赖注入方式，是通过客户类的构造函数，向客户类注入服务类实例。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;strong&gt;构造注入（Constructor Injection）是指在客户类中，设置一个服务类接口类型的数据成员，并以构造函数为注入点，这个构造函数接受一个具体的服务类实例为参数，并将它赋给服务类接口类型的数据成员。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;566&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/06_3.jpg&quot; height=&quot;311&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图3.3 构造注入示意&lt;/p&gt;
&lt;p&gt;图3.3是构造注入的示意图，可以看出，与Setter注入很类似，只是注入点由Setter方法变成了构造方法。这里要注意，由于构造注入只能在实例化客户类时注入一次，所以一点注入，程序运行期间是没法改变一个客户类对象内的服务类实例的。&lt;/p&gt;
&lt;p&gt;由于构造注入和Setter注入的IServiceClass，ServiceClassA和ServiceClassB是一样的，所以这里给出另外ClientClass类的示例代码。&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：ClientClass&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; ConstructorInjection&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; ClientClass&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; IServiceClass _serviceImpl;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; ClientClass(IServiceClass serviceImpl)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;._serviceImpl = serviceImpl;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; ShowInfo()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             Console.WriteLine(_serviceImpl.ServiceInfo());&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;可以看到，唯一的变化就是构造函数取代了Set_ServiceImpl方法，成为了注入点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1.3 依赖获取&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;上面提到的注入方式，都是客户类被动接受所依赖的服务类，这也符合&amp;ldquo;注入&amp;rdquo;这个词。不过还有一种方法，可以和依赖注入达到相同的目的，就是依赖获取。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;依赖获取（Dependency Locate）是指在系统中提供一个获取点，客户类仍然依赖服务类的接口。当客户类需要服务类时，从获取点主动取得指定的服务类，具体的服务类类型由获取点的配置决定。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可以看到，这种方法变被动为主动，使得客户类在需要时主动获取服务类，而将多态性的实现封装到获取点里面。获取点可以有很多种实现，也许最容易想到的就是建立一个Simple Factory作为获取点，客户类传入一个指定字符串，以获取相应服务类实例。如果所依赖的服务类是一系列类，那么依赖获取一般利用Abstract Factory模式构建获取点，然后，将服务类多态性转移到工厂的多态性上，而工厂的类型依赖一个外部配置，如XML文件。&lt;/p&gt;
&lt;p&gt;不过，不论使用Simple Factory还是Abstract Factory，都避免不了判断服务类类型或工厂类型，这样系统中总要有一个地方存在不符合OCP的if&amp;hellip;else或switch&amp;hellip;case结构，这种缺陷是Simple Factory和Abstract Factory以及依赖获取本身无法消除的，而在某些支持反射的语言中（如C#），通过将反射机制的引入彻底解决了这个问题（后面讨论）。&lt;/p&gt;
&lt;p&gt;下面给一个具体的例子，现在我们假设有个程序，既可以使用Windows风格外观，又可以使用Mac风格外观，而内部业务是一样的。&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;683&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/07_3.jpg&quot; height=&quot;709&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图3.4 依赖获取示意&lt;/p&gt;
&lt;p&gt;上图乍看有点复杂，不过如果读者熟悉Abstract Factory模式，应该能很容易看懂，这就是Abstract Factory在实际中的一个应用。这里的Factory Container作为获取点，是一个静态类，它的&amp;ldquo;Type构造函数&amp;rdquo;依据外部的XML配置文件，决定实例化哪个工厂。下面还是来看示例代码。由于不同组件的代码是相似的，这里只给出Button组件的示例代码，完整代码请参考文末附上的完整源程序。&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：按钮接口&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;interface&lt;/span&gt; IButton&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         String ShowInfo();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：Windows风格按钮&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; WindowsButton : IButton&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String Description { get; &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; WindowsButton()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Description = &lt;span style=&quot;color: #006080;&quot;&gt;&quot;Windows风格按钮&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String ShowInfo()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Description;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：Mac风格按钮&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; MacButton : IButton&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String Description { get; &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; MacButton()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Description = &lt;span style=&quot;color: #006080;&quot;&gt;&quot; Mac风格按钮&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; String ShowInfo()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;this&lt;/span&gt;.Description;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：工厂接口&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;interface&lt;/span&gt; IFactory&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         IWindow MakeWindow();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;         IButton MakeButton();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;         ITextBox MakeTextBox();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：Windows组件工厂&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; WindowsFactory : IFactory&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; IWindow MakeWindow()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; WindowsWindow();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; IButton MakeButton()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; WindowsButton();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; ITextBox MakeTextBox()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; WindowsTextBox();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：Mac组件工厂&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sealed&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; MacFactory : IFactory&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; IWindow MakeWindow()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; MacWindow();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; IButton MakeButton()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; MacButton();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; ITextBox MakeTextBox()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; MacTextBox();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：获取点&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Xml;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; FactoryContainer&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; IFactory factory { get; &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; FactoryContainer()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;             XmlDocument xmlDoc = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; XmlDocument();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;             xmlDoc.Load(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;http://www.cnblogs.com/Config.xml&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;             XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0].ChildNodes[0];&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #006080;&quot;&gt;&quot;Windows&quot;&lt;/span&gt; == xmlNode.Value)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;                 factory = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; WindowsFactory();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #006080;&quot;&gt;&quot;Mac&quot;&lt;/span&gt; == xmlNode.Value)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;                 factory = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; MacFactory();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  28:&lt;/span&gt;             {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  29:&lt;/span&gt;                 &lt;span style=&quot;color: #0000ff;&quot;&gt;throw&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; Exception(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;Factory Init Error&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  30:&lt;/span&gt;             }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  31:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  32:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  33:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：测试代码&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; Program&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;void&lt;/span&gt; Main(&lt;span style=&quot;color: #0000ff;&quot;&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;             IFactory factory = FactoryContainer.factory;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;             IWindow window = factory.MakeWindow();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;             Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;创建 &quot;&lt;/span&gt; + window.ShowInfo());&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;             IButton button = factory.MakeButton();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;             Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;创建 &quot;&lt;/span&gt; + button.ShowInfo());&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;             ITextBox textBox = factory.MakeTextBox();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;             Console.WriteLine(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;创建 &quot;&lt;/span&gt; + textBox.ShowInfo());&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;             Console.ReadLine();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;这里我们用XML作为配置文件。配置文件Config.xml如下：&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;xml&lt;/span&gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;=&quot;1.0&quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;encoding&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;=&quot;utf-8&quot;&lt;/span&gt; ?&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;Mac&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;可以看到，这里我们将配置设置为Mac风格，编译运行上述代码，运行结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;208&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/08_3.jpg&quot; height=&quot;119&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图3.5 配置Mac风格后的运行结果&lt;/p&gt;
&lt;p&gt;现在，我们不动程序，仅仅将配置文件中的&amp;ldquo;Mac&amp;rdquo;改为Windows，运行后结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;207&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/09_3.jpg&quot; height=&quot;107&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图3.6 配置为Windows风格后的运行结果&lt;/p&gt;
&lt;p&gt;从运行结果看出，我们仅仅通过修改配置文件，就改变了整个程序的行为（我们甚至没有重新编译程序），这就是多态性的威力，也是依赖注入效果。&lt;/p&gt;
&lt;p&gt;本节共讨论了三种基本的依赖注入类别，有关更多依赖注入类别和不同类别对比的知识，可以参考Martin Fowler的《&lt;a href=&quot;http://www.martinfowler.com/articles/injection.html&quot;&gt;Inversion of Control Containers and the Dependency Injection pattern&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.2 反射与依赖注入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;回想上面Dependency Locate的例子，我们虽然使用了多态性和Abstract Factory，但对OCP贯彻的不够彻底。在理解这点前，朋友们一定要注意潜在扩展在哪里，潜在会出现扩展的地方是&amp;ldquo;新的组件系列&amp;rdquo;而不是&amp;ldquo;组件种类&amp;rdquo;，也就是说，这里我们假设组件就三种，不会增加新的组件，但可能出现新的外观系列，如需要加一套Ubuntu风格的组件，我们可以新增UbuntuWindow、UbuntuButton、UbuntuTextBox和UbuntuFactory，并分别实现相应接口，这是符合OCP的，因为这是扩展。但我们除了修改配置文件，还要无可避免的修改FactoryContainer，需要加一个分支条件，这个地方破坏了OCP。依赖注入本身是没有能力解决这个问题的，但如果语言支持反射机制（Reflection），则这个问题就迎刃而解。&lt;/p&gt;
&lt;p&gt;我们想想，现在的难点是出在这里：对象最终还是要通过&amp;ldquo;new&amp;rdquo;来实例化，而&amp;ldquo;new&amp;rdquo;只能实例化当前已有的类，如果未来有新类添加进来，必须修改代码。如果，我们能有一种方法，不是通过&amp;ldquo;new&amp;rdquo;，而是通过类的名字来实例化对象，那么我们只要将类的名字作为配置项，就可以实现在不修改代码的情况下，加载未来才出现的类。所以，反射给了语言&amp;ldquo;预见未来&amp;rdquo;的能力，使得多态性和依赖注入的威力大增。&lt;/p&gt;
&lt;p&gt;下面是引入反射机制后，对上面例子的改进：&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;487&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/10_3.jpg&quot; height=&quot;670&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图3.7 引入反射机制的Dependency Locate&lt;/p&gt;
&lt;p&gt;可以看出，引入反射机制后，结构简单了很多，一个反射工厂代替了以前的一堆工厂，Factory Container也不需要了。而且以后有新组件系列加入时，反射工厂是不用改变的，只需改变配置文件就可以完成。下面给出反射工厂和配置文件的代码。&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #008080;&quot;&gt;Code：反射工厂&lt;/span&gt;
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Reflection;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;using&lt;/span&gt; System.Xml;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   8:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;namespace&lt;/span&gt; DependencyLocate&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   9:&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  10:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;internal&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;class&lt;/span&gt; ReflectionFactory&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  11:&lt;/span&gt;     {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  12:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; String _windowType;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  13:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; String _buttonType;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  14:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; String _textBoxType;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  15:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  16:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; ReflectionFactory()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  17:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  18:&lt;/span&gt;             XmlDocument xmlDoc = &lt;span style=&quot;color: #0000ff;&quot;&gt;new&lt;/span&gt; XmlDocument();&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  19:&lt;/span&gt;             xmlDoc.Load(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;http://www.cnblogs.com/Config.xml&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  20:&lt;/span&gt;             XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0];&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  21:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  22:&lt;/span&gt;             _windowType = xmlNode.ChildNodes[0].Value;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  23:&lt;/span&gt;             _buttonType = xmlNode.ChildNodes[1].Value;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  24:&lt;/span&gt;             _textBoxType = xmlNode.ChildNodes[2].Value;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  25:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  26:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  27:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; IWindow MakeWindow()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  28:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  29:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; Assembly.Load(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;DependencyLocate&quot;&lt;/span&gt;).CreateInstance(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;DependencyLocate.&quot;&lt;/span&gt; + _windowType) &lt;span style=&quot;color: #0000ff;&quot;&gt;as&lt;/span&gt; IWindow;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  30:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  31:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  32:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; IButton MakeButton()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  33:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  34:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; Assembly.Load(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;DependencyLocate&quot;&lt;/span&gt;).CreateInstance(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;DependencyLocate.&quot;&lt;/span&gt; + _buttonType) &lt;span style=&quot;color: #0000ff;&quot;&gt;as&lt;/span&gt; IButton;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  35:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  36:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  37:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;static&lt;/span&gt; ITextBox MakeTextBox()&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  38:&lt;/span&gt;         {&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  39:&lt;/span&gt;             &lt;span style=&quot;color: #0000ff;&quot;&gt;return&lt;/span&gt; Assembly.Load(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;DependencyLocate&quot;&lt;/span&gt;).CreateInstance(&lt;span style=&quot;color: #006080;&quot;&gt;&quot;DependencyLocate.&quot;&lt;/span&gt; + _textBoxType) &lt;span style=&quot;color: #0000ff;&quot;&gt;as&lt;/span&gt; ITextBox;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  40:&lt;/span&gt;         }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  41:&lt;/span&gt;     }&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;  42:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;配置文件如下：
&lt;div style=&quot;font-size: 8pt; overflow: visible; width: 100%; color: black; line-height: 12pt; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4; border-style: none; padding: 0px;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;xml&lt;/span&gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;=&quot;1.0&quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000;&quot;&gt;encoding&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;=&quot;utf-8&quot;&lt;/span&gt; ?&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   3:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;MacWindow&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   4:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;MacButton&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   5:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;textBox&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;MacTextBox&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;textBox&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #606060;&quot;&gt;   6:&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000;&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;反射不仅可以与Dependency Locate结合，也可以与Setter Injection与Construtor Injection结合。&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;反射机制的引入，降低了依赖注入结构的复杂度，使得依赖注入彻底符合OCP，并为通用依赖注入框架（如Spring.NET中的IoC部分、Unity等）的设计提供了可能性。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3 多态的活性与依赖注入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;color: #8000ff;&quot;&gt;&lt;strong&gt;重要声明：3.3节内容中诸多术语（包括但不限于&amp;ldquo;多态活性&amp;rdquo;、&amp;ldquo;高活多态性&amp;rdquo;、&amp;ldquo;中活多态性&amp;rdquo;、&amp;ldquo;低活多态性&amp;rdquo;、&amp;ldquo;多态时间空间稳定&amp;rdquo;）与诸多理论思想（包括但不限于&amp;ldquo;多态活性定义&amp;rdquo;、&amp;ldquo;根据活性分类多态&amp;rdquo;、&amp;ldquo;根据活性选择依赖注入类型&amp;rdquo;）均为笔者原创，所以，特声明以下两点：一、由于笔者水平所限，不保证其完全正确性和严格性，与前面诸多成熟理论相比，请批判性阅读；二、由于此节中诸多概念与思想理论已纳入笔者论文素材范畴，作为笔者原创成果，受法律保护。任何单位和个人不得擅自将此节内容部分或全部抄袭、改造、重新叙述成文进行公开发表。否则，笔者保留追究法律责任的权利。&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3.1 多态性的活性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这一节我们讨论多态的活性及其与依赖注入类型选择间密切的关系。&lt;/p&gt;
&lt;p&gt;首先说明，&amp;ldquo;多态的活性&amp;rdquo;这个术语是我个人定义的，因为我没有找到既有的概念名词可以表达我的意思，所以就自己造了一个词。这里，&lt;strong&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;某多态的活性是指被此多态隔离的变化所发生变化的频繁程度，频繁程度越高，则活性越强，反之亦然。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;上文说过，多态性可以隔离变化，但是，不同的变化，发生的频率是不一样的，这就使得多态的活性有所差别，这种差别影响了依赖注入的类型选择。&lt;/p&gt;
&lt;p&gt;举例来说，本文最开始提到的武器多态性，其活性非常高，因为在那个程序中，Role在一次运行中可能更换多次武器。而现在我们假设Role也实现了多态性，这是很可能的，因为在游戏中，不同类型的角色（如暗夜精灵、牛头人、矮人等）很多属性和业务是想通的，所以很可能通过一个IRole或AbstractRole抽象类实现多态性，不过，Role在实例化后（一般在用户登录成功后），是不会变化的，很少有游戏允许同一个玩家在运行中变换Role类型，所以Role应该是一但实例化，就不会变化，但如果再实例化一个（如另一个玩家登录），则可能就变化了。最后，还有一种多态性是活性非常低的，如我们熟悉的数据访问层多态性，即使我们实现了SQL Server、Oracle和Access等多种数据库的访问层，并实现了依赖注入，但几乎遇不到程序运行着就改数据库或短期内数据库频繁变动的情况。&lt;/p&gt;
&lt;p&gt;以上不同的多态性，不但特征不同，其目的一般也不同，总结如下：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;strong&gt;高活多态性&amp;mdash;&amp;mdash;指在客户类实例运行期间，服务类可能会改变的多态性。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;strong&gt;中活多态性&amp;mdash;&amp;mdash;指在客户类实例化后，服务类不会改变，但同一时间内存在的不同实例可能拥有不同类型的服务类。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;strong&gt;低活多态性&amp;mdash;&amp;mdash;指在客户类实例化后，服务类不会改变，且同一时间内所有客户类都拥有相同类型的服务类。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;以上三种多态性，比较好的例子就是上文提到的武器多态性（高活）、角色多态性（中活）和数据访问层多态性（低活）。另外，&lt;strong&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;我们说一种多态性是空间稳定的，如果同一客户类在同一时间内的所有实例都依赖相同类型的服务类，反之则叫做空间不稳定多态性。&lt;strong&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;我们说一种多态性是时间稳定的，如果一个客户类在实例化后，所以来的服务类不能再次更改，反之则叫做时间不稳定多态性。&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/strong&gt;显然，高活多态性时间和空间均不稳定；中活多态性是时间稳定的，但空间不稳定；低活多态性时间空间均稳定。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3.2 不同活性多态的依赖注入选择&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一般来说，&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;高活多态性适合使用Setter注入。&lt;/strong&gt;&lt;/span&gt;因为Setter注入最灵活，也是唯一允许在同一客户类实例运行期间更改服务类的注入方式。并且这种注入一般由上下文环境通过Setter的参数指定服务类类型，方便灵活，适合频繁变化的高活多态性。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;对于中活多态性，则适合使用Constructor注入。&lt;/strong&gt;&lt;/span&gt;因为Constructor注入也是由上下文环境通过Construtor的参数指定服务类类型，但一点客户类实例化后，就不能进行再次注入，保证了其时间稳定性。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;而对于低活多态性，则适合使用Dependency Locate并配合文件配置进行依赖注入，或Setter、Constructor配合配置文件注入，&lt;/strong&gt;&lt;/span&gt;因为依赖源来自文件，如果要更改服务类，则需要更改配置文件，一则确保了低活多态性的时间和空间稳定性，二是更改配置文件的方式方便于大规模服务类替换。（因为低活多态性一旦改变行为，往往规模很大，如替换整个数据访问层，如果使用Setter和Construtor传参，程序中需要改变的地方不计其数）&lt;/p&gt;
&lt;p&gt;本质上，这种选择是因为不同的依赖注入类型有着不同的稳定性，大家可以细细体会&amp;ldquo;活性&amp;rdquo;、&amp;ldquo;稳定性&amp;rdquo;和&amp;ldquo;依赖注入类型&amp;rdquo;之间密切的关系。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;4 IoC Container&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.1 IoC Container出现的必然性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;上面讨论了诸多依赖注入的话题。说道依赖注入，就不能不说IoC Container（IoC容器），那么到底什么是IoC容器？我们还是先来看看它的出现背景。&lt;/p&gt;
&lt;p&gt;我们知道，软件开发领域有句著名的论断：不要重复发明轮子！因为软件开发讲求复用，所以，对于应用频繁的需求，总是有人设计各种通用框架和类库以减轻人们的开发负担。例如，数据持久化是非常频繁的需求，于是各种ORM框架应运而生；再如，对MVC的需求催生了Struts等一批用来实现MVC的框架。&lt;/p&gt;
&lt;p&gt;随着面向对象分析与设计的发展和成熟，OOA&amp;amp;D被越来越广泛应用于各种项目中，然而，我们知道，用OO就不可能不用多态性，用多态性就不可能不用依赖注入，所以，依赖注入变成了非常频繁的需求，而如果全部手工完成，不但负担太重，而且还容易出错。再加上反射机制的发明，于是，自然有人开始设计开发各种用于依赖注入的专用框架。&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;strong&gt;这些专门用于实现依赖注入功能的组件或框架，就是IoC Container。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;从这点看，IoC Container的出现有其历史必然性。目前，最著名的IoC也许就是Java平台上的Spring框架的IoC组件，而.NET平台上也有Spring.NET和Unity等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.2 IoC Container的分类&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;前面曾经讨论了三种依赖注入方式，但是，想通过方式对IoC Container进行分类很困难，因为现在IoC Container都设计很完善，几乎支持所有依赖注入方式。不过，根据不同框架的特性和惯用法，还是可以讲IoC Container分为两个大类。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.2.1 重量级IoC Container&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所谓重量级IoC Container，是指一般用外部配置文件（一般是XML）作为依赖源，并托管整个系统各个类的实例化的IoC Container。这种IoC Container，一般是承接了整个系统几乎所有多态性的依赖注入工作，并承接了所有服务类的实例化工作，而且这些实例化依赖于一个外部配置文件，这种IoC Container，很像通过一个文件，定义整个系统多态结构，视野宏大，想要很好驾驭这种IoC Container，需要一定的架构设计能力和丰富的实践经验。&lt;/p&gt;
&lt;p&gt;Spring和Spring.NET是重量级IoC Container的例子。一般来说，这种IoC Container稳定性有余而活性不足，适合进行低活多态性的依赖注入。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.2.2 轻量级IoC Container&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;还有一种IoC Container，一般不依赖外部配置文件，而主要使用传参的Setter或Construtor注入，这种IoC Container叫做轻量级IoC Container。这种框架很灵活，使用方便，但往往不稳定，而且依赖点都是程序中的字符串参数，所以，不适合需要大规模替换和相对稳定的低活多态性，而对于高活多态性，有很好的效果。&lt;/p&gt;
&lt;p&gt;Unity是一个典型的轻量级IoC Container。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.3 .NET平台上典型IoC Container推介&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.3.1 Spring.NET&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;275&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/11_3.png&quot; height=&quot;88&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p&gt;Spring.NET是Java平台上Spring对.NET平台的移植，使用方法和Spring很像，并且功能强大，是.NET平台上大中型开发IoC Container的首选之一。除了DI外，Spring.NET也包括AOP等诸多功能。&lt;/p&gt;
&lt;p&gt;Spring.NET的官方网站是：&lt;a href=&quot;http://www.springframework.net/&quot;&gt;http://www.springframework.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.3.2 Unity&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;326&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/a5703ca6e7d5_D180/12_3.gif&quot; height=&quot;91&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt; &lt;/p&gt;
&lt;p&gt;对于小型项目和讲求敏捷的团队，Spring.NET可能有点太重量级，那么可以选择轻量级的Unity。Unity是微软patterns &amp;amp; practices团队推出的轻量级框架，非常好用，目前最新版本是1.2。&lt;/p&gt;
&lt;p&gt;Unity的官方网站是：&lt;a href=&quot;http://unity.codeplex.com/&quot;&gt;http://unity.codeplex.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参考文献&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[1]&amp;nbsp; Shivprasad koirala, Design pattern &amp;ndash; Inversion of control and Dependency injection, &lt;a href=&quot;http://www.codeproject.com/KB/aspnet/IOCDI.aspx&quot;&gt;http://www.codeproject.com/KB/aspnet/IOCDI.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2]&amp;nbsp; Martin Fowler, Inversion of Control Containers and the Dependency Injection pattern, &lt;a href=&quot;http://www.martinfowler.com/articles/injection.html&quot;&gt;http://www.martinfowler.com/articles/injection.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[3]&amp;nbsp; Paul, IoC Types, &lt;a href=&quot;http://docs.codehaus.org/display/PICO/IoC+Types&quot;&gt;http://docs.codehaus.org/display/PICO/IoC+Types&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[4]&amp;nbsp; Eric Freeman, Elisabeth Freeman. Head First Design Patterns. O&amp;rsquo;Reilly Media, 2004. ISBN 0596007142&lt;/p&gt;
&lt;p&gt;[5]&amp;nbsp; Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995. ISBN 0201633612&lt;/p&gt;
&lt;p&gt;[6]&amp;nbsp; Patrick Smacchia 著，施凡等 译，C#和.NET2.0 平台、语言与框架。2008.1，人民邮电出版&lt;/p&gt;
&lt;p&gt;[7]&amp;nbsp; Jeffrey Rechter 著，CLR via C#（影印版）。2008.8，人民邮电出版&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例代码下载：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;a rel=&quot;license&quot; target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot;&gt;&lt;img align=&quot;left&quot; src=&quot;http://i.creativecommons.org/l/by/2.5/cn/88x31.png&quot; alt=&quot;Creative Commons License&quot; style=&quot;border-width: 0px;&quot; /&gt;&lt;/a&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;本文基于&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot; title=&quot;Creative Commons Attribution 2.5 China Mainland License&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;署名 2.5 中国大陆&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;许可协议发布，欢迎转载，演绎或用于商业目的，但是必须保留本文的署名&lt;/span&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;张洋&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;（包含链接）。如您有任何疑问或者授权方面的协商，请&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://space.cnblogs.com/msg/send/leoo2sk&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;给我留言&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;。&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1504693.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 111　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717833/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717833/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717833/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 17 Jun 2009 00:26:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717833/5313554</fs:itemid></item><item><title>你真的了解分层架构吗？——写给被PetShop&amp;quot;毒害&amp;quot;的朋友们</title><link>http://www.cnblogs.com/leoo2sk/archive/2009/06/01/1494095.html</link><description>&lt;p&gt;阅读: 8616 评论: 121 作者: &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot; target=&quot;_blank&quot;&gt;EricZhang(T2噬菌体)&lt;/a&gt; 发表于 2009-06-01 23:02 &lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/06/01/1494095.html&quot; target=&quot;_blank&quot;&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;一叶障目&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;.NET平台上的分层架构（很多朋友称其为&amp;ldquo;三层架构&amp;rdquo;），似乎是一个长盛不衰的话题。经常看到许多朋友对其进行分析、探讨、辩论甚至是抨击。笔者在仔细阅读了大量这方面文章后，认为许多朋友在分层架构的理解上存在两个比较大的偏颇：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;1.没有从本质角度去理解分层的内涵，而只是了解其表象。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;2.对分层架构的理解过于狭隘，只是少数概念，而又不够深入。&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;许多朋友言&amp;ldquo;分层&amp;rdquo;则必称&amp;ldquo;DAL&amp;rdquo;、&amp;ldquo;BLL&amp;rdquo;、&amp;ldquo;表示层&amp;rdquo;等概念，殊不知&amp;ldquo;DAL&amp;rdquo;的内部还有&amp;ldquo;Data Source 架构模式&amp;rdquo;、&amp;ldquo;Object-Relational Behavioral 模式&amp;rdquo;、&amp;ldquo;Object-Relational Structural 模式&amp;rdquo;等方面，而其中每个方面下下又有诸多具体模式，如&amp;ldquo;Data Source 架构模式&amp;rdquo;又有&amp;ldquo;Table Data Gateway&amp;rdquo;、&amp;ldquo;Row Data Gateway&amp;rdquo;、&amp;ldquo;Acitive Record&amp;rdquo;等等。再说&amp;ldquo;BLL&amp;rdquo;，大家都知道&amp;ldquo;BLL&amp;rdquo;是&amp;ldquo;业务逻辑层&amp;rdquo;，可是什么是&amp;ldquo;业务逻辑&amp;rdquo;？&amp;ldquo;BLL&amp;rdquo;又可以构建为&amp;ldquo;Transaction Script&amp;rdquo;、&amp;ldquo;Domain Model&amp;rdquo;、&amp;ldquo;Table Module&amp;rdquo;三种模式，各是什么意思？另外，分层也不仅只有&amp;ldquo;数据访问层&amp;rdquo;+&amp;ldquo;业务逻辑层&amp;rdquo;+&amp;ldquo;表示层&amp;rdquo;这一种分法，诸如&amp;ldquo;服务层&amp;rdquo;、&amp;ldquo;持久化层&amp;rdquo;、&amp;ldquo;应用控制层&amp;rdquo;的概念朋友们是否真的熟悉呢。&lt;/p&gt;
&lt;p&gt;造成这种现象，我想很大一部分原因是因为大多数.NET平台的开发者（包括我在内）理解分层架构是从Microsoft的PetShop开始的。因为PetShop是官方的Demo，所以被众多.NET开发者奉为圣经，甚至成了.NET平台上分层架构的标准方案。我就曾看到许多朋友在我的博客中留下&amp;ldquo;分层架构还是PetShop最经典&amp;rdquo;、&amp;ldquo;想学分层还是看PetShop吧&amp;rdquo;、&amp;ldquo;你这是跟PetShop学得吧&amp;rdquo;这样的留言。朋友们太崇敬PetShop了，却忽略了一个事实：它仅仅是一个Demo。退一步说，即使它是一个实际应用的项目，这样通过一个具体项目去定义一个抽象概念的方式也是不科学的。&lt;/p&gt;
&lt;p&gt;举个例子，一个人不知道&amp;ldquo;牛&amp;rdquo;是什么东西，于是请教一位奶牛场管理员，管理员迁出一头奶牛，告诉他：&amp;ldquo;这就是牛&amp;rdquo;。从此以后，如果有人问他&amp;ldquo;牛&amp;rdquo;是什么，他就会告诉别人&amp;ldquo;牛&amp;rdquo;是一种体型庞大，行动笨拙，性格温顺，身上有黑白斑块图案，还有一个好大的咪咪，可以挤奶供人喝。有一天，他听说西班牙有斗牛这项运动，他大惊道：&amp;ldquo;这怎么可以！牛那么温顺，怎么能用来斗呢！而且牛是用来挤奶喝的啊！&amp;rdquo;&lt;/p&gt;
&lt;p&gt;故事中这个人犯了一个什么错误呢？他把&amp;ldquo;具体的一头奶牛&amp;rdquo;和&amp;ldquo;牛&amp;rdquo;这个抽象概念给划等号了。他认为牛就是&amp;ldquo;体型庞大，行动笨拙，性格温顺，身上有黑白斑块图案，还有一个好大的咪咪，可以挤奶供人喝&amp;rdquo;。殊不知这世界上还有黄牛、水牛、牦牛、斗牛、肉牛等各种牛。他没能做到&amp;ldquo;透过想象看本质&amp;rdquo;从而形成抽象概念，而犯了&amp;ldquo;一叶障目&amp;rdquo;的错误。&lt;/p&gt;
&lt;p&gt;其实，许多朋友之所以对分层架构理解片面或偏颇，是因为与故事中这个人犯了相同的错误。&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;当初，我们不知道何为&amp;ldquo;分层架构&amp;rdquo;，于是微软给了我们一个PetShop，说：&amp;ldquo;看！这就是.NET平台下分层架构的产品。&amp;rdquo;于是我们&amp;ldquo;恍然大悟&amp;rdquo;：&amp;ldquo;噢！这就是分层架构啊！&amp;rdquo;。就这样，我们把&amp;ldquo;分层架构&amp;rdquo;这样一个内涵和外延都极大的抽象概念和一个具体的Demo划了等号&lt;/strong&gt;&lt;/span&gt;，从而也变成了故事中那个人&amp;mdash;&amp;mdash;我们言分层架构必称DAL、BLL，我们做项目必然依照PetShop方式架构&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;我们确实被PetShop&amp;ldquo;毒害&amp;rdquo;了。但这不是微软的错，更不是PetShop的错，就像在故事中，我们不能把罪责归咎于奶牛场管理员或那头奶牛。错在我们自己！&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;当微软给我们PetShop时，我们应该在脑中清醒认识到：这是一个分层架构的Demo。而不是理解成了&amp;ldquo;这就是分层架构&amp;rdquo;。&lt;/strong&gt;&lt;/span&gt;我们应该钻研、思考，从而抓住分层架构的本质，可是我们没有。&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;与其说我们是被PetShop&amp;ldquo;毒害&amp;rdquo;了，倒不如说我们是被自己、被自己那种不良的学习习惯毒害了。&lt;/strong&gt;&lt;/span&gt;我们仅看表象，还是只看了一个表象，然后就冒然对分层架构盖棺定论。而没能透过想象看本质。所以，我们同样犯了&amp;ldquo;一叶障目&amp;rdquo;的错误。&lt;/p&gt;
&lt;p&gt;以上的错误，笔者也曾经犯过！所以，在下文中，我想和朋友们一起分享一下我在反省自己的过程中，悟出的一些心得体会，希望能借此帮助更多朋友尽快走出&amp;ldquo;一叶障目&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;洞悉分层的本质&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以讨论如何分层，可以讨论分层的利弊，可以讨论分层有没有价值&amp;hellip;&amp;hellip;但在这一切一切讨论之前，我们要先弄清楚一件事：分层的本质是什么？或者说：分层是怎么来的？如果这个问题不明晰，那么我们其他的讨论犹如&amp;ldquo;浮沙之上筑高台&amp;rdquo;，再精辟的言辞，如果没有一个牢固的基础，也是站不住脚的。&lt;/p&gt;
&lt;p&gt;想要了解分层的本质，就不得不说说分工。分工可以说是劳动生产力上最大的改良，最初分工的好处体现在&amp;ldquo;比较优势&amp;rdquo;上，由于各司其职，每个人可以从事其最擅长的劳动，再加上单纯劳动所带来的劳动熟练度提升和减少了更换劳动时的损失，使得劳动生产率大幅提升。然而，随着社会的发展，我们发现某些特殊形式的分工不但可以提高生产力，还有另一些好处！为了理解这些好处，我们举个实际的例子。&lt;/p&gt;
&lt;p&gt;今天是六一国际儿童节，一位母亲想给她的女儿买一个奶油蛋糕作为礼物。我们知道，蛋糕需要面粉、需要鸡蛋、需要牛奶等等，还需呀经过一系列复杂的加工和包装过程，但是这位母亲不需要关心这些，她只要去附近的超市直接买就行了。而超市里既没有养鸡场，也没有奶牛场，更没有种小麦的农民伯伯和烘焙蛋糕的工人师傅。这个简单的&amp;ldquo;买蛋糕&amp;rdquo;场景，大约可以用下图表示。&lt;/p&gt;
&lt;p&gt;&lt;img border=&quot;0&quot; width=&quot;307&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/leoo2sk/WindowsLiveWriter/PetShop_C3DB/1_3.gif&quot; height=&quot;690&quot; style=&quot;display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;图1、制作蛋糕的分工&lt;/p&gt;
&lt;p&gt;图1大约说明了一个蛋糕是如何从到达顾客手里的。可以看到，制作蛋糕不是一个单一的劳动，需要许多的分工，如果自底向上看，主要的分工包括：基础物质资料的种植生产、原料加工、蛋糕加工、商业销售。并不是所有分工都如上图这样，上图所示的分工，有一些特点，下面总结一下。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;1.下层不知道上层的存在。&lt;/span&gt;&lt;/strong&gt;例如奶牛厂生产牛奶，它不必知道牛奶被拿去做什么，可能被奶油厂收购去做奶油，也可能被雪糕厂收购了做雪糕，也可能被收购去做奶糖，总之，它只管完成自己的职责&amp;mdash;&amp;mdash;生产牛奶，而对于它的上层一无所知。同样，奶油加工厂只管生产奶油，它不必知道奶油被拿去做蛋糕还是做摩卡咖啡。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;2.每一层仅仅知道它的下一层（最后一层除外，因为最后一层没有下一层），而不知道另外的下层。&lt;/strong&gt;&lt;/span&gt;例如，蛋糕厂只需知道从面粉厂、奶油厂和鸡蛋厂提取面粉、奶油、鸡蛋就行了，而不必关心面粉是怎么来了、奶油是怎么来的这些问题。&lt;/p&gt;
&lt;p&gt;可以说，符合以上两点的分工就是分层架构的思想来源。下面说的稍微正式一点。&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;所谓分层思想，就是这样一种分工：它将系统按不同的职责组织成有序的层次。其中，除最上层外，每一层仅提供若干服务供其相邻的上层使用，但不知道上层的存在；除最下层外，每一层仅调用其临近下层的服务。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;所以，所谓&amp;ldquo;分层思想&amp;rdquo;，不过是一种特殊的分工形式。而计算机软件架构中的分层思想，是将这一思想应用于软件开发中的特例，而PetShop所使用的&amp;ldquo;DAL+BLL+PL&amp;rdquo;的方式，又不过是将这一思想应用于软件开发中的特例的特例。例如，如果某个系统的业务很简单，仅仅是增删改查，那么BLL就没有作用，&amp;ldquo;DAL+PL&amp;rdquo;的方式就可以很好完成，这也是很好的分层架构。再如，如果某个系统的业务很复杂，需要先规格化，再做运算，再做整理，那么&amp;ldquo;DAL+规格化层+计算层+整理层+PL&amp;rdquo;这种五层架构也是很合理的啊。如果某个系统BLL所暴露的接口太繁杂，那么使用Facade模式在BLL和PL之间加一个&amp;ldquo;Facade Service Layer&amp;rdquo;也是很正常的。再者，如果某个系统不需要数据存取功能，例如计算器程序，我们只是想把表示和业务（计算功能）分开，那么就没有DAL了，&amp;ldquo;BLL+PL&amp;rdquo;就是合理的。所以，用分层的思想进行架构，本质是&amp;ldquo;将系统按不同职责组织成有序层次&amp;hellip;&amp;hellip;&amp;rdquo;这一段话描述的，而不是简单&amp;ldquo;将系统分成DAL+BLL+PL&amp;rdquo;，更不是&amp;ldquo;按PetShop的方式进行架构&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;下面，摘录一段Fowler在《Patterns of Enterprise Application Architecture》中对分层的定义：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;em&gt;When thinking of a system in terms of layers, you imagine the principal subsystem in the software arranged in some form of layer cake,where each layer rests on lower layer. In this scheme the higher layer uses various services defined by lower layer,but lower layer is unaware of the higher layer. Furthemore, each layer usally hides its lower layers from the layers above.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;mdash;&amp;mdash;Martin Fowler, 《Patterns of Enterprise Application Architecture》, P17&lt;/p&gt;
&lt;p&gt;大致译文如下：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0080c0;&quot;&gt;&lt;em&gt;当我们说一个系统是分层架构的时候，你可以把这个软件想象成一个有很多层的蛋糕的样子，其中每一层放在它的下一层上。较高层使用诸多较低层定义和提供的服务，但较低层并没有察觉较高层的存在。另外，每一层都会对其上层隐藏更低的层。&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;mdash;&amp;mdash;马丁 福勒, 《企业应用架构模式》, P17&lt;/p&gt;
&lt;p&gt;但是，这里有一点需要声明：虽然说&amp;ldquo;DAL+BLL+PL&amp;rdquo;不等价于分层架构，而仅仅是一种实例。但同时我们要清楚的认识到，这个方式之所以如此流行，以至于微软的官方示例都这样架构，是因为对于许多系统，特别是大中型MIS系统，这种架构方式是应该优先考虑的。在这一节中，笔者绝对没有对&amp;ldquo;DAL+BLL+PL&amp;rdquo;进行批判的意思，相反，当开发系统时，这种方式可以优先考虑，然后可以根据系统的特点，进行一定得改良。笔者在本节所强调的是：不能把&amp;ldquo;DAL+BLL+PL&amp;rdquo;看做分层架构的本质，更不能和&amp;ldquo;分层架构&amp;rdquo;这个思想概念划等号。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;分层架构的利弊分析&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在理解了分层架构的本质的基础上，我们才可以放心大胆的对分层架构进行利弊分析。废话少讲，这一节我们直接切入正题。&lt;/p&gt;
&lt;p&gt;分层架构的优点如下：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;1.分离开发人员的关注。&lt;/strong&gt;&lt;/span&gt;由于某一层仅仅调用其相邻下一层所提供的服务，所以，只要本层的API和相邻下一层的API定义完整，开发人员在开发某一层时就可以像关注集中于这一层所用的思想、模式、技术，这样，就等同于将分工带来的生产力提高优势引入软件开发。又如买蛋糕的例子，作为超市，只要知道下层API（如何从蛋糕厂获取蛋糕）和本层需要实现的API（把蛋糕销售给客户），就可以制定自己的业务模式很策略计划了，而不必关心如何种小麦、如何磨面粉、如何做奶油、如何做蛋糕等。这样，超市只需进行商业运作，而不必进行产业运作，如此专一，必然提高业务水平。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;2.无损替换。&lt;/strong&gt;&lt;/span&gt;想象一下，如果某家奶牛场倒闭了，奶油加工厂也要跟着倒闭吗？当然不会，它可以迅速更换一家奶牛场，因为各个奶牛场都可以实现&amp;ldquo;提供牛奶&amp;rdquo;这项服务。再譬如，如果某天国家出台政策，要求所有奶油厂必须从审查合格的奶牛场引进原料，恰好某奶油厂的合作牛奶供应商没能通过审查，那么，只要换一家通过审查的合作就行了。而且奶油厂内部的各个环节一动不用动，因为不同的奶牛场都可以提供&amp;ldquo;供应牛奶&amp;rdquo;这个服务。而如果奶油厂自己养牛生产牛奶，一旦遇到这个政策，还得自己去有关部门进行审查，调整相应业务流程，牵一发而动全身。程序中同样的道理，最常听说的可能就是迁移数据库了。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;3.降低了系统间的依赖。&lt;/strong&gt;&lt;/span&gt;还是蛋糕那个例子，如果某天蛋糕厂内部换机器了，或业务流程调整了，请问顾客需要关心吗？显然不用，因为顾客只调用超市提供的服务。而超市为顾客隐藏了下面所有产业细节。如果每一个顾客买一样商品，都要了解这个商品从原料生产到成型再到销售的一系列细节，岂不累死了。换做程序中，就如表示层只管调用业务层的服务，至于业务层下还有几层？各种数据是怎么来的？怎么存的？是真实的还是捏造的？都不需要了解，这大大降低了系统各职责之间的依赖。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;4.复用。&lt;/span&gt;&lt;/strong&gt;例如，你可以去这个超市买东西，我也可以去这个超市买东西。蛋糕厂可以从面粉厂提取面粉，馒头厂也可以。这样，同样的层就可以为不同的上层提供服务，达到了复用的目的。具体到程序中，例如气象局制作发布了一个&amp;ldquo;Service Layer&amp;rdquo;，用于提供天气预告信息。这样新浪、搜狐这些网站可以利用这个服务层提供的服务，制作天气预告页面，QQ也可以利用这个服务在它的聊天工具上添加天气预告，你自己做一个软件需要用到天气预告功能，也可以调用气象台的&amp;ldquo;Service Layer&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;说罢优点，再来谈谈分层架构的弊端：&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;1.级联修改问题。&lt;/strong&gt;&lt;/span&gt;这个问题在现实中不好比喻，但在程序中相信很多朋友都明白。例如，一个人事管理系统，本来查看人员信息只能分页查看，而现在，需要增加一个功能：在分页的同时还能分部门。例如，可以查看&amp;ldquo;销售部的前50个人&amp;rdquo;，这样，为了这个功能所有层都需要修改。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color: #ff8000;&quot;&gt;2.性能问题。&lt;/span&gt;&lt;/strong&gt;本来直来直去的操作，现在要层层传递，势必造成性能的下降。就如在购买蛋糕的例子中。顾客在享受分工带来的便利时，也要承受由于不同层的部门分布各地而造成的蛋糕价格上升，这是因为分层增加了成本，如运输、不同层间部门的协调管理成本等。&lt;/p&gt;
&lt;p&gt;纵观以上分析，分层架构有利有弊。这是一定得，世上任何事物都有利弊，所以，把&amp;ldquo;分层架构捧上天&amp;rdquo;和&amp;ldquo;一棍子打死&amp;rdquo;这两种做法都是不明智也是不科学的。对待分层架构，我们的态度应当是明晰其本质和利弊，然后根据具体情况做出理性的分析和抉择。&lt;/p&gt;
&lt;p&gt;从上面的分析可以看出，分层架构可以降低层内变化的成本，而对于API的变化非常敏感。如在级联修改中提到的&amp;ldquo;在分页的同时还能分部门&amp;rdquo;的新需求，就是对API进行的变动。API的变动对于分层架构是致命的，修改起来难度非常大。所以，一个简单的判断法则就是：&lt;span style=&quot;color: #ff8000;&quot;&gt;&lt;strong&gt;如果您的系统层内频繁变动（甚至整层替换）可能性很大，而API变动可能性很小，就使用分层；而如果API可能会频繁变动，那就要谨慎使用分层架构了。&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;&lt;strong&gt;后面的话&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;其实，我想说的主要内容，就是前面三节了。不过还是有些话，想和大家唠叨唠叨。&lt;/p&gt;
&lt;p&gt;这篇文章，不是一篇技术文章，所以通篇不提技术细节，而只是想帮大家澄清对分层的误解。最近看了很多对分层架构（或三层架构）的探讨，其中以批判居多，有的甚至认为分层就是个没用的垃圾东西。我想，产生这种想法的人，大致经过了以下阶段：听说分层，粗略学习分层、模仿使用分层、用得十分不爽、出来批判。&lt;/p&gt;
&lt;p&gt;其实，任何技术都是客观的，都没有错误，错误在人，是人没有正确使用，或没有用到合适的地方。就像我们不能批判刀片不适合劈叉，也不能批判柴刀不适合刮胡子。一项技术想要发挥威力，关键要正确运用，而要正确运用，就需要有深厚的功底，需要我们努力学习，勤于思考。这不是一朝一夕的事情，要有持久的毅力。我们要争取做一个善于用功、善于把握事物本质的人，而不是一个用刀片劈柴、用柴刀刮胡子，然后大骂刀片和柴刀都是垃圾的人。&lt;/p&gt;
&lt;p&gt;分层思想从来就不是软件架构中首先提出来的，我们天天上网用到的网络，都遵循OSI七层协议，网络结构的设计是分层思想合理应用的一个典范。另外，在许多其他工程技术领域，分层思想也是很普遍的。所以，不要把分层当成计算机人士甚至软件开发人士独有的能力，相对那些领域，将分层应用于软件架构的技术还很不成熟，还有许多事情等待我们去做。&lt;/p&gt;
&lt;p&gt;最后强烈推荐一本书：Martin Fowler的《Patterns of Enterprise Application Architecture》，相信看完这本书，对于分层思想的理解和分层中具体模式的运用决策都会有大幅提高。你会明白，原来分层不是只有&amp;ldquo;DAL&amp;rdquo;、&amp;ldquo;BLL&amp;rdquo;，原来分层还有怎么多内在的东西。&lt;/p&gt;
&lt;p&gt;最后祝大家六一快乐！：）&lt;/p&gt;
&lt;div id=&quot;MySignature&quot;&gt;&lt;a rel=&quot;license&quot; target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot;&gt;&lt;img align=&quot;left&quot; src=&quot;http://i.creativecommons.org/l/by/2.5/cn/88x31.png&quot; alt=&quot;Creative Commons License&quot; style=&quot;border-width: 0px;&quot; /&gt;&lt;/a&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;本文基于&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://creativecommons.org/licenses/by/2.5/cn/&quot; title=&quot;Creative Commons Attribution 2.5 China Mainland License&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;署名 2.5 中国大陆&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;许可协议发布，欢迎转载，演绎或用于商业目的，但是必须保留本文的署名&lt;/span&gt;&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;张洋&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;（包含链接）。如您有任何疑问或者授权方面的协商，请&lt;/span&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://space.cnblogs.com/msg/send/leoo2sk&quot;&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;给我留言&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;。&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src=&quot;http://www.cnblogs.com/leoo2sk/aggbug/1494095.html?type=1&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;p&gt;评论: 121　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/06/01/1494095.html#pagedcomment&quot; target=&quot;_blank&quot;&gt;查看评论&lt;/a&gt;　&lt;a href=&quot;http://www.cnblogs.com/leoo2sk/archive/2009/06/01/1494095.html#commentform&quot; target=&quot;_blank&quot;&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;最新新闻：&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56793/&quot; target=&quot;_blank&quot;&gt;知名扩展 Firebug 的简化版登陆 Chrome&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:59)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56792/&quot; target=&quot;_blank&quot;&gt;Google 悄悄地启用 1e100.net，打枪地不要&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:57)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56791/&quot; target=&quot;_blank&quot;&gt;从 Google 代码库找到的好东西&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:46)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56789/&quot; target=&quot;_blank&quot;&gt;苹果在线商店临时关闭 或将推新Macbook&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 22:39)&lt;/span&gt;&lt;br/&gt;· &lt;a href=&quot;http://news.cnblogs.com/n/56788/&quot; target=&quot;_blank&quot;&gt;豆瓣网推出豆瓣电台iPhone客户端&lt;/a&gt;&lt;span style=&quot;color:gray&quot;&gt;(2010-02-09 21:51)&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;编辑推荐：&lt;a href=&quot;http://news.cnblogs.com/n/56782/&quot; target=&quot;_blank&quot;&gt;2010年2月编程语言排行榜&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href=&quot;http://www.cnblogs.com&quot; target=&quot;_blank&quot;&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/&quot; target=&quot;_blank&quot;&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://news.cnblogs.com&quot; target=&quot;_blank&quot;&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/ing/&quot; target=&quot;_blank&quot;&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://home.cnblogs.com/group/&quot; target=&quot;_blank&quot;&gt;小组&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com/q/&quot; target=&quot;_blank&quot;&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://space.cnblogs.com&quot; target=&quot;_blank&quot;&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://kb.cnblogs.com&quot; target=&quot;_blank&quot;&gt;知识库&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/330717846/T2sNotebook/feedsky/s.gif?r=http://www.cnblogs.com/leoo2sk/archive/2009/06/01/1494095.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/T2sNotebook/330717846/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/T2sNotebook/330717846/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Mon, 01 Jun 2009 23:02:00 +0800</pubDate><author>EricZhang(T2噬菌体)</author><guid isPermaLink="false">http://www.cnblogs.com/leoo2sk/archive/2009/06/01/1494095.html</guid><dc:creator>EricZhang(T2噬菌体)</dc:creator><fs:srclink>http://www.cnblogs.com/leoo2sk/archive/2009/06/01/1494095.html</fs:srclink><fs:srcfeed>http://www.cnblogs.com/leoo2sk/rss</fs:srcfeed><fs:itemid>feedsky/T2sNotebook/~7204453/330717846/5313554</fs:itemid></item></channel></rss>