23种常见的设计模式(5):建造者模式

1,026次阅读
没有评论

还是咋们的电脑店,不过今天的客户有点不同寻常。还记得上次那个我们给装了9900K CPU的客户吗?没错,今天他又来了。但是今天他的需求有点不同寻常,他要装300套和之前配置一样的电脑,用来开一个巨豪华的网咖。对于我们来说当然高兴呀,而且这生意可不能黄了。但是单单靠我们几个人肯定不行呀,等装完300台电脑,黄花菜都凉了。

于是我们请了两个经验丰富的临时工来帮我们组装一下。那么问题就来了,临时工他们两个人的装配顺序不一样,每个人有每个人的工作习惯,但是肯定要按照客户的要求,按照之前配置来装电脑呀。于是我们就做出规定,对于电脑配件的装配顺序可以不一样,但是要安装的配件必须是我们列出来的。

既然如此,我们就先把模板制定出来:

public abstract class IComputerDiy
{
    private List<SequenceItem> _sequence = null;

    public void SetSequence(List<SequenceItem> sequence)
    {
        if (sequence == null || sequence.Count == 0)
        {
            throw new Exception("一定要按照步骤来,虽然我不管你的步骤是什么样的。");
        }
        if(sequence.Count != 5)
        {
            throw new Exception("不能漏掉任何一步哦。");
        }
        this._sequence = sequence;
    }

    /// <summary>
    /// 组装的电脑肯定要能给跑起来才是一台合格的电脑
    /// </summary>
    public void Run()
    {
        foreach (var item in _sequence)
        {
            switch (item)
            {
                case SequenceItem.POWER:
                    this.AddPower();
                    break;
                case SequenceItem.CPU:
                    this.AddCPU();
                    break;
                case SequenceItem.RAM:
                    this.AddRAM();
                    break;
                case SequenceItem.BOARD:
                    this.AddBoard();
                    break;
                case SequenceItem.DISK:
                    this.AddDisk();
                    break;
            }
        }
    }

    /// <summary>
    /// 安装电源
    /// </summary>
    public abstract void AddPower();

    /// <summary>
    /// 安装主板
    /// </summary>
    public abstract void AddBoard();

    /// <summary>
    /// 安装CPU
    /// </summary>
    public abstract void AddCPU();

    /// <summary>
    /// 安装内存条
    /// </summary>
    public abstract void AddRAM();

    /// <summary>
    /// 安装硬盘
    /// </summary>
    public abstract void AddDisk();
}

然后是我们要装配的产品,用Intel芯片的电脑。

/// <summary>
/// 用Intel CPU的性能很强劲的电脑
/// </summary>
public class IntelPowerfulPC : IComputerDiy
{
    public override void AddBoard()
    {
        Console.WriteLine("我是Z390的主板,我装INTEL的CPU。");
    }

    public override void AddCPU()
    {
        Console.WriteLine("我是CPU 9900K,嗯~我很保值。");
    }

    public override void AddDisk()
    {
        Console.WriteLine("我是硬盘,我叫傲腾905p。");
    }

    public override void AddPower()
    {
        Console.WriteLine("我是电源,海韵的哦~");
    }

    public override void AddRAM()
    {
        Console.WriteLine("我是内存,32GB DDR4 4000MHZ。");
    }
}

我们招聘临时工是干嘛的?帮我们组装产品的,所以我们对他们进行约束,不然他们划水了怎么办。

/// <summary>
/// 装配者
/// </summary>
public abstract class IComputerBuilder
{
    public abstract IComputerDiy Product();
}

然后是我们招聘的老师傅,分别叫小明和王五,我们可以称他们为建造者:

/// <summary>
/// 我是临时工小明
/// </summary>
public class ComputerBuilderXiaoMing : IComputerBuilder
{
    private readonly IComputerDiy _computer = new IntelPowerfulPC();

    private void SetSequsence()
    {
        List<SequenceItem> sequences = new List<SequenceItem>();
        sequences.Add(SequenceItem.DISK);
        sequences.Add(SequenceItem.BOARD);
        sequences.Add(SequenceItem.CPU);
        sequences.Add(SequenceItem.RAM);
        sequences.Add(SequenceItem.POWER);

        _computer.SetSequence(sequences);
    }

    public override IComputerDiy Product()
    {
        SetSequsence();
        return _computer;
    }
}

/// <summary>
/// 我是临时工王五
/// </summary>
public class ComputerBuilderWangWu : IComputerBuilder
{
    private readonly IComputerDiy _computer = new IntelPowerfulPC();

    private void SetSequsence()
    {
        List<SequenceItem> sequences = new List<SequenceItem>();
        sequences.Add(SequenceItem.BOARD);
        sequences.Add(SequenceItem.CPU);
        sequences.Add(SequenceItem.RAM);
        sequences.Add(SequenceItem.DISK);
        sequences.Add(SequenceItem.POWER);

        _computer.SetSequence(sequences);
    }

    public override IComputerDiy Product()
    {
        SetSequsence();
        return _computer;
    }
}

当然,还需要我们来进行协调指挥。

public class BOSS
{
    /// <summary>
    /// 小明组装1台
    /// </summary>
    /// <returns></returns>
    public IComputerDiy GetXiaoMingProduct()
    {
        return new ComputerBuilderXiaoMing().Product();
    }

    /// <summary>
    /// 王五组装1台
    /// </summary>
    /// <returns></returns>
    public IComputerDiy GetWangWuProduct()
    {
        return new ComputerBuilderWangWu().Product();
    }

    /// <summary>
    /// 小明组装30台
    /// </summary>
    /// <returns></returns>
    public List<IComputerDiy> GetXiaoMingProducts()
    {
        List<IComputerDiy> products = new List<IComputerDiy>();
        for (int i = 0; i < 30; i++)
        {
            products.Add(new ComputerBuilderXiaoMing().Product());
        }
        return products;
    }

    /// <summary>
    /// 王五组装35台
    /// </summary>
    /// <returns></returns>
    public List<IComputerDiy> GetWangWuProducts()
    {
        List<IComputerDiy> products = new List<IComputerDiy>();
        for (int i = 0; i < 35; i++)
        {
            products.Add(new ComputerBuilderWangWu().Product());
        }
        return products;
    }
}

这样,我们的小作坊就开工啦,开始为土豪老板装电脑。工作了一天,我们来看看装配结果:

static void Main(string[] args)
{
    IComputerDiy result;
    BOSS boss = new BOSS();

    Console.WriteLine("小明装的电脑:");
    result = boss.GetXiaoMingProduct();
    result.Run();

    Console.WriteLine();
    Console.WriteLine("王五装的电脑:");
    result = boss.GetWangWuProduct();
    result.Run();

    Console.WriteLine();
    Console.WriteLine($"我是小明,我今天装了{boss.GetXiaoMingProducts().Count}台:");
    Console.WriteLine($"我是王五,我今天装了{boss.GetWangWuProducts().Count}台:");

    Console.ReadKey(false);
}

运行结果:

23种常见的设计模式(5):建造者模式
建造者模式demo运行结果

分析上面的例子,很容易就能发现,建造者模式分为了三层。最下面是要生产的产品,中间是建造者(Builder),不同的建造者按照不同的规则去完成产品的生产。最上面是指挥者(Director),指挥建造者生产对应的产品。这样的分层结构让代码很清晰,很容易就能理解,也是建造者模式的一大优点。说了这么多,不难理解建造者模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

另外,在建造者模式中,也可以将指挥者去掉。去掉指挥者,我们自己去调用建造者即可。最终是否需要指挥者还需要看应用场景。

23种常见的设计模式(5):建造者模式
建造者模式通用类图

再来看一下建造者模式的优缺点和应用场景。

优点:

· 调用人员无需关心建造者内部实现,直接调用对外提供的方法即可。即拥有良好的封装性。
· 易于扩展,建造者不够了,创建一个即可。
· 代码清晰,易于理解。

缺点:

貌似没啥缺点~~

综上所述,当遇到相同的方法要产生不同的结果时,就可以使用建造者模式。但在使用的时候也需要灵活搭配,可能一个需求的实现是多个设计模式共同作用之后产生的美妙结果,一个系统就更别说了。

最后,对比与工厂方法模式,它们是不是有很多相同之处呢?特别是最后的调用方式,可以说是毫无区别。但它们最大的不同之处又在什么地方呢?

afirefish
版权声明:本站原创文章,由afirefish2020-01-04发表,共计4632字。
转载提示:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
载入中...