C#设计模式(5)——建造者模式(Builder Pattern)

原文:C#设计模式(5)——建造者模式(Builder Pattern)

一、引言

  在软件系统中,有时需要创建一个复杂对象,并且这个复杂对象由其各部分子对象通过一定的步骤组合而成。例如一个采购系统中,如果需要采购员去采购一批电脑时,在这个实际需求中,电脑就是一个复杂的对象,它是由CPU、主板、硬盘、显卡、机箱等组装而成的,如果此时让采购员一台一台电脑去组装的话真是要累死采购员了,这里就可以采用建造者模式来解决这个问题,我们可以把电脑的各个组件的组装过程封装到一个建造者类对象里,建造者只要负责返还给客户端全部组件都建造完毕的产品对象就可以了。然而现实生活中也是如此的,如果公司要采购一批电脑,此时采购员不可能自己去买各个组件并把它们组织起来,此时采购员只需要像电脑城的老板说自己要采购什么样的电脑就可以了,电脑城老板自然会把组装好的电脑送到公司。下面就以这个例子来展开建造者模式的介绍。

二、建造者模式的详细介绍

2.1 建筑者模式的具体实现

  在这个例子中,电脑城的老板是直接与客户(也就是指采购员)联系的,然而电脑的组装是由老板指挥装机人员去把电脑的各个部件组装起来,真真负责创建产品(这里产品指的就是电脑)的人就是电脑城的装机人员。理清了这个逻辑过程之后,下面就具体看下如何用代码来表示这种现实生活中的逻辑过程:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5
  6
  7 /// <summary>
  8 /// 以组装电脑为例子
  9 /// 每台电脑的组成过程都是一致的,但是使用同样的构建过程可以创建不同的表示(即可以组装成不一样的电脑,配置不一样)
 10 /// 组装电脑的这个场景就可以应用建造者模式来设计
 11 /// </summary>
 12 namespace 设计模式之建造者模式
 13 {
 14     /// <summary>
 15     /// 客户类
 16     /// </summary>
 17     class Customer
 18     {
 19         static void Main(string[] args)
 20         {
 21             // 客户找到电脑城老板说要买电脑,这里要装两台电脑
 22             // 创建指挥者和构造者
 23             Director director = new Director();
 24             Builder b1 = new ConcreteBuilder1();
 25             Builder b2 = new ConcreteBuilder2();
 26
 27             // 老板叫员工去组装第一台电脑
 28             director.Construct(b1);
 29
 30             // 组装完,组装人员搬来组装好的电脑
 31             Computer computer1 = b1.GetComputer();
 32             computer1.Show();
 33
 34             // 老板叫员工去组装第二台电脑
 35             director.Construct(b2);
 36             Computer computer2 = b2.GetComputer();
 37             computer2.Show();
 38
 39             Console.Read();
 40         }
 41     }
 42
 43     /// <summary>
 44     /// 小王和小李难道会自愿地去组装嘛,谁不想休息的,这必须有一个人叫他们去组装才会去的
 45     /// 这个人当然就是老板了,也就是建造者模式中的指挥者
 46     /// 指挥创建过程类
 47     /// </summary>
 48     public class Director
 49     {
 50         // 组装电脑
 51         public void Construct(Builder builder)
 52         {
 53             builder.BuildPartCPU();
 54             builder.BuildPartMainBoard();
 55         }
 56     }
 57
 58     /// <summary>
 59     /// 电脑类
 60     /// </summary>
 61     public class Computer
 62     {
 63         // 电脑组件集合
 64         private IList<string> parts = new List<string>();
 65
 66         // 把单个组件添加到电脑组件集合中
 67         public void Add(string part)
 68         {
 69             parts.Add(part);
 70         }
 71
 72         public void Show()
 73         {
 74             Console.WriteLine("电脑开始在组装.......");
 75             foreach (string part in parts)
 76             {
 77                 Console.WriteLine("组件"+part+"已装好");
 78             }
 79
 80             Console.WriteLine("电脑组装好了");
 81         }
 82     }
 83
 84     /// <summary>
 85     /// 抽象建造者,这个场景下为 "组装人" ,这里也可以定义为接口
 86     /// </summary>
 87     public abstract class Builder
 88     {
 89         // 装CPU
 90         public abstract void BuildPartCPU();
 91         // 装主板
 92         public abstract void BuildPartMainBoard();
 93
 94         // 当然还有装硬盘,电源等组件,这里省略
 95
 96         // 获得组装好的电脑
 97         public abstract Computer GetComputer();
 98     }
 99
100     /// <summary>
101     /// 具体创建者,具体的某个人为具体创建者,例如:装机小王啊
102     /// </summary>
103     public class ConcreteBuilder1 : Builder
104     {
105         Computer computer = new Computer();
106         public override void BuildPartCPU()
107         {
108             computer.Add("CPU1");
109         }
110
111         public override void BuildPartMainBoard()
112         {
113             computer.Add("Main board1");
114         }
115
116         public override Computer GetComputer()
117         {
118             return computer;
119         }
120     }
121
122     /// <summary>
123     /// 具体创建者,具体的某个人为具体创建者,例如:装机小李啊
124     /// 又装另一台电脑了
125     /// </summary>
126     public class ConcreteBuilder2 : Builder
127     {
128         Computer computer = new Computer();
129         public override void BuildPartCPU()
130         {
131             computer.Add("CPU2");
132         }
133
134         public override void BuildPartMainBoard()
135         {
136             computer.Add("Main board2");
137         }
138
139         public override Computer GetComputer()
140         {
141             return computer;
142         }
143     }
144 }

上面代码中都有详细的注释代码,这里就不过多解释,大家可以参考代码和注释来与现实生活中的例子做对比,下图展示了上面代码的运行结果:

2.2 建造者模式的定义和类图

  介绍完了建造者模式的具体实现之后吗,下面具体看下建造者模式的具体定义是怎样的。

建造者模式(Builder Pattern):将一个复杂对象的构建于它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式使得建造代码与表示代码的分离,可以使客户端不必知道产品内部组成的细节,从而降低了客户端与具体产品之间的耦合度,下面通过类图来帮助大家更好地理清建造者模式中类之间的关系。

三、建造者模式的分析

介绍完了建造者模式的具体实现之后,让我们总结下建造模式的实现要点:

  1. 在建造者模式中,指挥者是直接与客户端打交道的,指挥者将客户端创建产品的请求划分为对各个部件的建造请求,再将这些请求委派到具体建造者角色,具体建造者角色是完成具体产品的构建工作的,却不为客户所知道。
  2. 建造者模式主要用于“分步骤来构建一个复杂的对象”,其中“分步骤”是一个固定的组合过程,而复杂对象的各个部分是经常变化的(也就是说电脑的内部组件是经常变化的,这里指的的变化如硬盘的大小变了,CPU由单核变双核等)。
  3. 产品不需要抽象类,由于建造模式的创建出来的最终产品可能差异很大,所以不大可能提炼出一个抽象产品类。
  4. 在前面文章中介绍的抽象工厂模式解决了“系列产品”的需求变化,而建造者模式解决的是 “产品部分” 的需要变化。
  5. 由于建造者隐藏了具体产品的组装过程,所以要改变一个产品的内部表示,只需要再实现一个具体的建造者就可以了,从而能很好地应对产品组成组件的需求变化。

四、.NET 中建造者模式的实现

  前面的设计模式在.NET类库中都有相应的实现,那在.NET 类库中,是否也存在建造者模式的实现呢? 然而对于疑问的答案是肯定的,在.NET 类库中,System.Text.StringBuilder(存在mscorlib.dll程序集中)就是一个建造者模式的实现。不过它的实现属于建造者模式的演化,此时的建造者模式没有指挥者角色和抽象建造者角色,StringBuilder类即扮演着具体建造者的角色,也同时扮演了指挥者和抽象建造者的角色,此时建造模式的实现如下:

 /// <summary>
    /// 建造者模式的演变
    /// 省略了指挥者角色和抽象建造者角色
    /// 此时具体建造者角色扮演了指挥者和建造者两个角色
    /// </summary>
    public class Builder
    {
        // 具体建造者角色的代码
        private Product product = new Product();
        public void BuildPartA()
        {
            product.Add("PartA");
        }
        public void BuildPartB()
        {
            product.Add("PartB");
        }
        public Product GetProduct()
        {
            return product;
        }
        // 指挥者角色的代码
        public void Construct()
        {
            BuildPartA();
            BuildPartB();
        }
    }

    /// <summary>
    /// 产品类
    /// </summary>
    public class Product
    {
        // 产品组件集合
        private IList<string> parts = new List<string>();

        // 把单个组件添加到产品组件集合中
        public void Add(string part)
        {
            parts.Add(part);
        }

        public void Show()
        {
            Console.WriteLine("产品开始在组装.......");
            foreach (string part in parts)
            {
                Console.WriteLine("组件" + part + "已装好");
            }

            Console.WriteLine("产品组装完成");
        }
    }

    // 此时客户端也要做相应调整
    class Client
    {
        private static Builder builder;
        static void Main(string[] args)
        {
            builder = new Builder();
            builder.Construct();
            Product product = builder.GetProduct();
            product.Show();
            Console.Read();
        }
    }

  StringBuilder类扮演着建造string对象的具体建造者角色,其中的ToString()方法用来返回具体产品给客户端(相当于上面代码中GetProduct方法)。其中Append方法用来创建产品的组件(相当于上面代码中BuildPartA和BuildPartB方法),因为string对象中每个组件都是字符,所以也就不需要指挥者的角色的代码(指的是Construct方法,用来调用创建每个组件的方法来完成整个产品的组装),因为string字符串对象中每个组件都是一样的,都是字符,所以Append方法也充当了指挥者Construct方法的作用。

五、总结

  到这里,建造者模式的介绍就结束了,建造者模式(Builder Pattern),将一个复杂对象的构建与它的表示分离,使的同样的构建过程可以创建不同的表示。建造者模式的本质是使组装过程(用指挥者类进行封装,从而达到解耦的目的)和创建具体产品解耦,使我们不用去关心每个组件是如何组装的。

本专题中所有源码: 建造者模式源码

时间: 2024-11-10 01:03:51

C#设计模式(5)——建造者模式(Builder Pattern)的相关文章

乐在其中设计模式(C#) - 建造者模式(Builder Pattern)

原文:乐在其中设计模式(C#) - 建造者模式(Builder Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 建造者模式(Builder Pattern) 作者:webabcd 介绍 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 示例 用同样的构建过程创建Sql和Xml的Insert()方法和Get()方法. MessageModel using System;using System.Collections.Generic;using Sy

理解java设计模式之建造者模式_java

建造者模式(Builder Pattern)主要用于"分步骤构建一个复杂的对象",在这其中"分步骤"是一个稳定的算法,而复杂对象的各个部分则经常变化.因此, 建造者模式主要用来解决"对象部分"的需求变化. 这样可以对对象构造的过程进行更加精细的控制. package com.shejimoshi.create.Builder; /** * 功能:意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 * 适用性: * 当创

【设计模式】—— 创建者模式Builder

模式意图 一个对象的创建十分复杂,为了区分构建过程和使用过程,因此分开.使用一个Director类进行对象的创建,Builder规定了这个创建过程. 模式结构 Builder 抽象建造者接口,规范各个组成部分的构建. ConcreteBuilder 具体建造者角色,实现组成部分的构建,并提供示例. Product 产品角色,创建返回的对象. Director 导演者角色,负责创建以及使用. 使用场景 1 当创建对象复杂并且与其使用过程独立. 2 构造过程允许构造的对象有不同的表示. 代码结构 B

深入理解JavaScript系列(27):设计模式之建造者模式详解

 这篇文章主要介绍了深入理解JavaScript系列(27):设计模式之建造者模式详解,建造者模式可以将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示,需要的朋友可以参考下     介绍 在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成:由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定.如何应对这种变化?如何提供一种"封装机制"来隔离出"复

乐在其中设计模式(C#) - 备忘录模式(Memento Pattern)

原文:乐在其中设计模式(C#) - 备忘录模式(Memento Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 备忘录模式(Memento Pattern) 作者:webabcd 介绍 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到保存的状态. 示例 有一个Message实体类,某个对象对它的操作有Insert()方法,只有在插入时间符合要求的情况下才能插入成功,因此要求可以保存和恢复Message对象的状态,插入失败

乐在其中设计模式(C#) - 代理模式(Proxy Pattern)

原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为其他对象提供一个代理以控制对这个对象的访问. 示例 有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对象的访问. MessageModel using System;using System.Collections.Generic;using Sy

乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)

原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabcd 介绍 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 示例 有一个Message实体类,某些对象对它的操作有Insert()和Get()方法,现在要针对其中某一方法进行操作. MessageModel using System;using

乐在其中设计模式(C#) - 状态模式(State Pattern)

原文:乐在其中设计模式(C#) - 状态模式(State Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它所属的类. 示例 有一个Message实体类,对它的操作有Insert()和Get()方法,持久化数据在SqlServer数据库中或Xml文件里.在对象内部可以根据用户的不同选择不同的数据持久化方案. MessageModel using

乐在其中设计模式(C#) - 提供者模式(Provider Pattern)

原文:乐在其中设计模式(C#) - 提供者模式(Provider Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 提供者模式(Provider Pattern) 作者:webabcd 介绍 为一个API进行定义和实现的分离. 示例 有一个Message实体类,对它的操作有Insert()和Get()方法,持久化数据在SqlServer数据库中或Xml文件里.根据配置文件中的配置来决定数据持久化方案是使用SqlServer数据库还是Xml文件. MessageModel us