[设计模式系列] 建造者

Posted Andy阿辉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[设计模式系列] 建造者相关的知识,希望对你有一定的参考价值。

建造者(生成器)模式

含义:生成器模式是一种创建型模式,使你能够分步奏创建复杂对象。可是使用相同的创建代码生成不同类型和形式的对象。


看图我们就能很好地理解,图中就是工厂中的流水线模式,建造者就好比整条流水线,通过流水线上每个装配点的工人将一个个产品零件组装整合成一个完整的产品即可。

生成器模式结构

  1. 生成器(Builder)接口声明在所有类型生成器中通用的产品构造步奏。
  2. 具体生成器(Concrete Builders)提供构造过程的不同实现,具体生成器也可以构造不遵循通用接口的产品。
  3. 产品(Products)是最终生成的对象。由不同生成器构造的产品无需数据同一类层次结构或接口。
  4. 主管(Director)类定义调用构造步奏的顺序,这样就可以创建和复用特定的产品配置。

Demo展示

这里我就拿极速物流公司中发货的过程来举例,希望大家能对建造者模式有一个很好的理解。

这里不同地区收费不一样给出报价单的业务就可以使用我们刚刚学习到的建造者模式来实现,由于不同地方的运输路径,发货方式,包装方式等不同,则收费标准也是不一样的。

类结构描述

  • 发货货物类(基本属性)

  • 发货抽象类(生成器)

  • 各自不同地区的收费类(具体生成器,生成器的实现类)

  • 发货的控制类(主管)

```c#
/// <summary>
/// 物流公司发货基类
/// 运输方式、包装样式、运输类型
/// </summary>
public class Matter
{
/// <summary>
/// 包装样式
/// </summary>
public string PackStyle{get;set;}
/// <summary>
/// 运输方式
/// </summary>
public string TransportWay { get; set; }
/// <summary>
/// 是否有税费
/// </summary>
public string IsHaveTax { get; set; }
/// <summary>
/// 总金额
/// </summary>
/// <returns></returns>
public double Money { get; set; }
/// <summary>
/// 描述信息
/// </summary>
public string DescriptionInfo { get; set; }
}


```c#
 /// <summary>
    /// 发货实现类 :抽象建造者
    /// </summary>
    public abstract class SendModelBuilder
    {
        protected Matter matter = new Matter();

        public abstract void BuilderPackStyle();

        public abstract void BuilderTransportWay();

        public abstract void BuilderIsHaveTax();

        public abstract void BuilderMoney();

        public abstract void BuilderDescriptionInfo();

        /// <summary>
        /// 返回一个完整得发货实现类
        /// </summary>
        /// <returns></returns>
        public Matter CreateMatter()
        {
            return matter;
        }
    }

```c#
/// <summary>
/// 日本地区创建者
/// </summary>
public class RiBenBuilder : SendModelBuilder
{
public override void BuilderPackStyle()
{
matter.PackStyle = "木质箱子包装";
}

    public override void BuilderTransportWay()
    {
        matter.TransportWay = "水路";
    }

    public override void BuilderIsHaveTax()
    {
        matter.IsHaveTax = "有";
    }

    public override void BuilderMoney()
    {
        matter.Money = 1000;
    }

    public override void BuilderDescriptionInfo()
    {
        matter.DescriptionInfo = "此次运输为水路运输,货物为木质箱子包装,有税费,金额为1000元";
    }
}

```c#
    /// <summary>
    /// 北京地区创建者
    /// </summary>
    public class BeiJingBuilder : SendModelBuilder
    {
        public override void BuilderPackStyle()
        {
            matter.PackStyle = "纸盒";
        }

        public override void BuilderTransportWay()
        {
            matter.TransportWay = "陆运";
        }

        public override void BuilderIsHaveTax()
        {
            matter.IsHaveTax = "有";
        }

        public override void BuilderMoney()
        {
            matter.Money = 50;
        }

        public override void BuilderDescriptionInfo()
        {
            matter.DescriptionInfo = "此次运输为陆运运输,货物为纸盒包装,无税费,金额为50元";
        }
    }

```c#
/// <summary>
/// 印度地区创建者
/// </summary>
public class YinDuBuilder : SendModelBuilder
{
public override void BuilderPackStyle()
{
matter.PackStyle = "纸盒包装";
}

    public override void BuilderTransportWay()
    {
        matter.TransportWay = "空运";
    }

    public override void BuilderIsHaveTax()
    {
        matter.IsHaveTax = "有";
    }

    public override void BuilderMoney()
    {
        matter.Money = 3000;
    }

    public override void BuilderDescriptionInfo()
    {
        matter.DescriptionInfo = "此次运输为空运,货物为纸盒包装,有税费,金额为3000元";
    }
}

```c#
    /// <summary>
    /// 急速物流发货创建控制器
    /// </summary>
    public class JiSuWuLiuController
    {
        public Matter SendModel(SendModelBuilder builder) 
        {
            builder.BuilderPackStyle();
            builder.BuilderTransportWay();
            builder.BuilderIsHaveTax();
            builder.BuilderMoney();
            builder.BuilderDescriptionInfo();
            return builder.CreateMatter();
        }
    }

上面罗列出的就是各个类的具体代码实现,下面是测试,目前以北京地区发货举例。

```c#
class Program
{
static void Main(string[] args)
{
SendModelBuilder smb = new BeiJingBuilder();
JiSuWuLiuController director = new JiSuWuLiuController();
Matter matter = director.SendModel(smb);
Console.WriteLine("包装类型:"+matter.PackStyle);
Console.WriteLine("运输方式:" + matter.TransportWay);
Console.WriteLine("是否有税费:" + matter.IsHaveTax);
Console.WriteLine("运费:" + matter.Money);
Console.WriteLine("信息:"+matter.DescriptionInfo);
Console.ReadKey();
}
}


![测试结果](https://s4.51cto.com/images/blog/202109/13/ab35d1311a5267027bfc31aa4f7a9dc9.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

可以看到,我们在实现的时候,只是去声明并由directior来调用了BeiJingBuilder的创建者,具体的业务也只是单独在BeiJingBuilder类中去实现。如果我们想换成其余地区的发货,则只需要将声明换掉就可以。

## 小结

**优点:**

- 客户端不需要知道产品内部的组成细节,将产品本身与产品的创建进行分离,也就是解耦,使得相同的创建过程可以创建不同的产品对象。

- 具体构建着独立,增加新的建造者不需要修改原有库,系统扩展方便,符合开闭原则。

- 控制产品的创建过程很方便。

**缺点:**

- 当产品比较多时,导致代码比较冗余,系统变得过于庞大,增加系统的理解难度和运行成本。

- 此模式主要适用于当各自产品有一定共性的时候,如果产品独立性太强,无相同共性则不适合这个模式。
 ## 小寄语

人生短暂,我不想去追求自己看不见的,我只想抓住我能看的见的。

我是**阿辉**,感谢您的阅读,如果对你有帮助,麻烦点赞、转发  谢谢。

以上是关于[设计模式系列] 建造者的主要内容,如果未能解决你的问题,请参考以下文章

设计模式从青铜到王者第八篇:创建型模式之建造者模式(BuilderPattern)

设计模式学习系列——建造者模式

建造者模式

设计模式总结篇系列:建造者模式(Builder)

设计模式系列 - 建造者模式

设计模式 - 创建型模式_建造者模式