zoukankan      html  css  js  c++  java
  • 设计模式(4)建造者模式/生成器模式(Builder)

    设计模式(0)简单工厂模式

    设计模式(1)单例模式(Singleton)

    设计模式(2)工厂方法模式(Factory Method)

    设计模式(3)抽象工厂模式(Abstract Factory)

    源码地址

    0 建造者模式简介

    0.0 建造者模式定义

    建造者模式是一种常见的创建型模式,也称生成器模式。建造者模式的一般书面化定义为:将一个复杂对象的构建与该对象的表示分离,使得同样的构建过程可以创建不同的表示

    建造者模式主要用于构建复杂产品,并且该产品是可以步骤化或者模块化的,最终可以根据步骤或模块组装创建出一个复杂产品。

    现实生活中我们每天都在使用的手机有不同品牌不同型号,千差万别,但他们都具有屏幕、电池、外壳、核心(CPU、GUPU、ROM、RAM等)共性模块,即他们的创建过程是一致的,变化的只是每个步骤/模块的详细实现细节。这种情景是使用创建者模式的最佳时机,最终产品构建过程是统一且固定的,我们将变化的部分交给建造者,只需要配置不同的建造者,就可以使同样的构建过程生产出完全不同的产品。

    建造者模式的结构图如下

    103735-21dae004efea8394

    Director:指导者,主要用来使用Buider接口,以一个统一固定的过程生产最终的产品Product

    Builder:建造者抽象接口,定义创建一个Product对象所需各个部件的操作。在该接口中一般要求包含创建部件的方法如buidPartA,buidPartB等,同时还要包含一个获取最终创建的复杂对象的方法getResult()。builder可以定义为一个抽象类或者接口

    ConcreteBuilder:具体的建造者实现,继承自Builder接口,实现接口中定义的创建部件及返回产品的方法。在这里不同的创建者实现类,对同一部件或步骤进行不同的详细实现,来完成不同产品的创建。

    Product:最终产品类,表示被建造者构建出来的复杂对象,其用于多个固定的部件或步骤。

    0.1 建造者模式应用场景

    我们以英雄祭坛里造英雄这一过程为例。在使用模式之前,我们最直接的代码应该像下面这样。

    恶魔猎手创建类

    /// <summary>
    /// 恶魔猎手创建类
    /// </summary>
    public class DH
    {
        /// <summary>
        /// 创建英雄
        /// </summary>
        /// <returns></returns>
        public string BuilderHero()
        {
           string body = "黑夜给了我黑色眼睛,我却用它去寻找光明。"; // 创建身体
            string weapon = "艾辛诺斯双刃。"; // 创建武器
            string mount = "我有这双脚有这双腿。"; // 创建坐骑
            return body + weapon + mount;
        }
    }

    同样,月之女祭司创建类

    /// <summary>
    /// 月之女祭司创建类
    /// </summary>
    public class POM
    {
        /// <summary>
        /// 创建英雄
        /// </summary>
        /// <returns></returns>
        public string BuilderHero()
        {
           string body = "夜幕只为朱颜改,群星陨落无穷。"; // 创建身体
            string weapon = "索利达尔·群星之怒。"; // 创建武器
            string mount = "艾斯卡达尔。"; // 创建坐骑
            return body + weapon + mount;
        }
    }

    客户调用时只需要实例化不同的英雄创建类,来完成对应英雄的创建。

    DH dh = new DH();
    Console.WriteLine(dh.BuilderHero());
    POM pom = new POM();
    Console.WriteLine(pom.BuilderHero());
    Console.ReadLine();

    这样我们需要别的英雄时只需要再添加一个创建该英雄对应的类。

    我们这里只是简单的通过一句话描述创建了英雄身体、武器、坐骑三个关键部位,而实际中一个复杂产品的构件过程是远远要复杂的多,比如我们常见的文件导出,一个文件有头、内容、尾部说明三类内容,导出txt格式跟导出xml格式的操作,每个部位的创建都要根据不同的格式进行处理。

    同时我们发现这样一种情况,每个英雄创建类中创建英雄的方法其实都是同一种模式,处理步骤完全一样,唯一变化的部分就在于每个步骤的具体实现细节,我们自然会考虑

    1、创建每个英雄都要用到同样的步骤,对与固定不变的部分,我们要提炼出来,形成统一且公用的处理过程

    2、英雄不只这两个,还会有很多其他英雄需要创建,要求我们在处理过程不变的情况下,能实现创建不同英雄的需要

    也就是说,我们的固定不变的处理过程应该和变化的具体实现分离,从而达到固定处理过程的复用,同时还能满足不同具体实现的需求,此时的需求已经和前面介绍过的建造者模式非常贴近了。

    1 建造者模式详解

    0、提炼具体产品类

    将上面用字符串表示的英雄的三个特征使用一个英雄类表示

    /// <summary>
    /// 英雄类
    /// </summary>
    public class Hero
    {
        /// <summary>
        /// 身体特征
        /// </summary>
        public string Body { get; set; }
    
        /// <summary>
        /// 武器
        /// </summary>
        public string Weapon { get; set; }
    
        /// <summary>
        /// 坐骑
        /// </summary>
        public string Mount { get; set; }
    }

    1、建造者接口

    建造者接口包含创建各部位的方法定义,及获取最终产品方法的定义

    /// <summary>
    /// 建造者接口
    /// </summary>
    public interface IBuilder
    {
        /// <summary>
        /// 创建身体特征
        /// </summary>
        /// <returns></returns>
        void BuildBody();
    
        /// <summary>
        /// 创建武器
        /// </summary>
        /// <returns></returns>
        void BuildWepon();
    
        /// <summary>
        /// 创建坐骑
        /// </summary>
        /// <returns></returns>
        void BuildMount();
    
        /// <summary>
        /// 获取最终产品
        /// </summary>
        /// <returns></returns>
        Hero GetResult();
    }

    2、建造者具体实现类

    恶魔猎手建造者实现类

    /// <summary>
    /// 恶魔猎手建造者实现类
    /// </summary>
    public class DHBuilder : IBuilder
    {
        private Hero _hero = new Hero();
    
        /// <summary>
        /// 创建身体特征
        /// </summary>
        /// <returns></returns>
        public void BuildBody()
        {
            _hero.Body = "黑夜给了我黑色眼睛,我却用它去寻找光明。";
        }
    
        /// <summary>
        /// 创建武器
        /// </summary>
        /// <returns></returns>
        public void BuildWeapon()
        {
            _hero.Weapon= "艾辛诺斯双刃。";
        }
    
        /// <summary>
        /// 创建坐骑
        /// </summary>
        /// <returns></returns>
        public void BuildMount()
        {
            _hero.Mount= "我有这双脚有这双腿。";
        }
    
        public Hero GetResult()
        {
            return _hero;
        }
    }

    月之女祭司建造者类实现

    /// <summary>
    /// 月之女祭司建造者类
    /// </summary>
    public class POMBuilder : IBuilder
    {
        private Hero _hero = new Hero();
    
        /// <summary>
        /// 创建身体特征
        /// </summary>
        /// <returns></returns>
        public void BuildBody()
        {
            _hero.Body = "夜幕只为朱颜改,群星陨落无穷。";
        }
    
        /// <summary>
        /// 创建武器
        /// </summary>
        /// <returns></returns>
        public void BuildWeapon()
        {
            _hero.Weapon = "索利达尔·群星之怒。";
        }
    
        /// <summary>
        /// 创建坐骑
        /// </summary>
        /// <returns></returns>
        public void BuildMount()
        {
            _hero.Mount = "艾斯卡达尔。";
        }
    
        /// <summary>
        /// 创建最终产品
        /// </summary>
        /// <returns></returns>
        public Hero GetResult()
        {
            return _hero;
        }
    
    }

    3 、指导者实现

    /// <summary>
    /// 指导者
    /// </summary>
    public class Director
    {
        /// <summary>
        /// 指导方法
        /// </summary>
        public void Construct(IBuilder builder)
        {
           builder.BuildBody(); // 创建身体特征
            builder.BuildWeapon(); // 创建武器
            builder.BuildMount(); // 创建坐骑
        }
    }

    4、客户端调用

    Director director = new Director();
    
    DHBuilder buider1 = new DHBuilder();
    director.Construct(buider1);
    Hero dh = buider1.GetResult();
    
    DHBuilder buider2 = new DHBuilder();
    director.Construct(buider2);
    Hero pom = buider1.GetResult();

    2 总结

    建造者模式具有一下优点

    1、松散耦合

    建造者模式把产品的构建过程独立出来,实现产品构建和产品表现的分离,从而使得构建算法可以复用,同时具体产品表现也可以灵活的扩展和切换。

    2、可以很容易改变产品内部表示

    在建造者模式中,Builder只提供接口给Director使用,具体的部件创建和装配方式有具体的创建者实现类实现,Director不关注具体实现细节,这样一来,如果像改变产品内部的表示,只需要修改具体建造者实现类即可。

    3、更好的复用性

    固定建造过程可以复用

  • 相关阅读:
    「beta不只是为了测试」​​​​​​​​​​​​​​​​​​写出我心(一百八十八)​
    「多尝试换一种思路」​​​​​​​​​​​​​​​​​​写出我心(一百八十七)
    「先给事情排个优先级」​​​​​​​​​​​​​​​​​​写出我心(一百八十六)
    「为达目标,不折手段」​​​​​​​​​​​​​​​​​写出我心(一百八十五)
    「迈出第一步」​​​​​​​​​​​​​​​​写出我心(一百八十四)
    「认真思考,果断提问」​​​​​​​​​​​​​​​写出我心(一百八十三)
    「提高阅读速度的4个步骤」​​​​​​​​​​​​​​写出我心(一百八十二)
    「一行精华」​​​​​​​​​​​​​写出我心(一百八十一)
    「阅读的量要大于质」写出我心(一百八十)
    Programming Concepts: Static vs. Dynamic Type Checking
  • 原文地址:https://www.cnblogs.com/fonour/p/7412450.html
Copyright © 2011-2022 走看看