zoukankan      html  css  js  c++  java
  • 设计模式的征途—6.建造者(Builder)模式

    建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低的创建型模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。因为,没有人买车会只买一个方向盘或者轮胎,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件组成的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需要解决的问题。

    建造者模式(Builder) 学习难度:★★★★☆ 使用频率:★★☆☆☆

    一、从游戏角色设计谈起

    M公司游戏开发部想要开发一款名为Manulife群侠传的网络游戏,该游戏采用主流的RPG(角色扮演游戏)模式,玩家可以在游戏中扮演各种特定的角色,而各个角色又可以根据不同的游戏情节和统计数据(如力量、魔法、技能等)具有不同的能力,角色也会随着不断升级而拥有更加强大的能力。

    作为RPG游戏的一个重要组成部分,需要对游戏角色进行设计,而且随着该游戏的升级将不断增加新的角色。不同类型的游戏角色,其性别、脸型、服装、发型等外部特性都有所差异,例如“天使”拥有美丽的面容和披肩的长发,并身穿一袭白裙;而“恶魔”则极其丑陋,留着光头并穿着一件刺眼的黑衣。

    M公司决定开发一个小工具来创建游戏角色,可以创建不同类型的角色并可以灵活地增加新角色。

               

      【几种不同的角色:恶魔,天使和英雄】

      M公司的开发人员分析发现,游戏角色是一个复杂对象,它包含性别、脸型等多个组成部分,不同的游戏角色其组成部分有所差异,如上图所示。无论是何种造型的游戏角色,其创建步骤都大同小异,都需要逐步创建其组成部分,再将各组成部分装配成个一个完整的游戏角色。如何一步一步地创建一个包含多个组成部分的复杂对象,建造者模式为解决此类问题而诞生。

    二、建造者模式概述

    2.1 建造者模式关键定义

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

      建造者模式是一种较为复杂的创建型模式,他将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无需知道复杂对象的内部组成与装配方式,主需要知道所需的建造者即可。其关注点在于如何一步一步地创建一个复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无需修改已有代码,系统具有较好的可扩展性。

      

      从上图可以看出,建造者模式包含以下三类重要角色;

      (1)Builder(抽象建造者):为创建一个产品对象的各个部件指定抽象接口,在其接口中一般包含两类方法:一类是BuildPartX(),用于创建复杂对象的各个部件;另一类是GetResult(),用于返回生成好的复杂对象。它就可以是抽象类,也可以是接口。

      (2)ConcreteBuilder(具体建造者):实现了Builder接口,即实现了各个部件的具体构造和装配方法,定义并明确其所创建的复杂对象。

      (3)Product(产品角色):被构建的复杂对象,包含多个组成部件。

      (3)Director(指挥者):负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其Construct()方法中调用建造者对象的部件构造和装配方法,完成复杂对象的建造。因此,客户端只需要和指挥者进行交互,这也确保了单一职责。

    2.2 建造者模式典型实现

      (1)复杂对象:包含多个成员变量的对象,这些成员也称为部件或零件。一个典型的复杂对象类如下:

        public class Product
        {
            public string PartA { get; set; }
            public string PartB { get; set; }
            public string PartC { get; set; }
        }

      (2)抽象建造者:定义了产品的创建和返回方法。

        public abstract class Builder
        {
            // 创建产品对象
            protected Product product = new Product();
    
            public abstract void BuildPartA();
            public abstract void BuildPartB();
            public abstract void BuildPartC();
    
            // 返回产品对象
            public Product GetResult()
            {
                return product;
            }
        }

      (3)指挥者对象:控制整个产品的创建过程。

        public class Director
        {
            private Builder builder;
    
            public Director(Builder builder)
            {
                this.builder = builder;
            }
    
            public void SetBuilder(Builder builder)
            {
                this.builder = builder;
            }
    
            // 产品构建与组装方法
            public Product Construct()
            {
                builder.BuildPartA();
                builder.BuildPartB();
                builder.BuildPartC();
    
                return builder.GetResult();
            }
        }

    2.3 建造者模式与抽象工厂模式的对比

      建造者模式与抽象工厂模式有点相似,但是建造者模式返回一个完整的复杂产品,而抽象工厂模式则返回一系列相关的产品。如果将抽象工厂模式看成一个汽车配件生产厂,生成不同类型的汽车配件,那么建造者模式则是一个汽车组装厂,通过对配件进行组成返回一辆完整的汽车

    三、游戏角色设计实现方案

    3.1 方案结构图

      以建造者模式为基础来实现游戏角色的设计,其中ActorController充当指挥者(Director),ActorBuilder充当抽象建造者,HeroBuilder、AngelBuilder和DevilBuilder充当具体建造者,Actor充当复杂产品。

    3.2 具体实现

      (1)Actor:复杂产品

        /// <summary>
        /// Actor 角色类 : 复杂产品,这里只列出部分成员变量
        /// </summary>
        public class Actor
        {
            // 角色类型
            public string Type { get; set; }
            // 性别
            public string Sex { get; set; }
            // 脸型
            public string Face { get; set; }
            // 服装
            public string Costume { get; set; }
            // 发型
            public string HairStyle { get; set; }
        }

      (2)ActorBuilder:抽象建造者

        /// <summary>
        /// 角色建造器 : 抽象建造者
        /// </summary>
        public abstract class ActorBuilder
        {
            protected Actor actor = new Actor();
    
            public abstract void BuildType();
            public abstract void BuildSex();
            public abstract void BuildFace();
            public abstract void BuildCostume();
            public abstract void BuildHairStyle();
    
            // 工厂方法 : 返回一个完整的游戏角色对象
            public Actor CreateActor()
            {
                return actor;
            }
        }

      (3)HeroBuilder、AngelBuilder和DevilBuilder:具体建造者

        /// <summary>
        /// 天使角色建造器 :具体建造者
        /// </summary>
        public class AngelBuilder : ActorBuilder
        {
            public override void BuildCostume()
            {
                actor.Costume = "白裙";
            }
    
            public override void BuildFace()
            {
                actor.Face = "漂亮";
            }
    
            public override void BuildHairStyle()
            {
                actor.HairStyle = "披肩长发";
            }
    
            public override void BuildSex()
            {
                actor.Sex = "";
            }
    
            public override void BuildType()
            {
                actor.Type = "天使";
            }
        }
    
        /// <summary>
        /// 恶魔角色建造器 :具体建造者
        /// </summary>
        public class DevilBuilder : ActorBuilder
        {
            public override void BuildCostume()
            {
                actor.Costume = "黑衣";
            }
    
            public override void BuildFace()
            {
                actor.Face = "丑陋";
            }
    
            public override void BuildHairStyle()
            {
                actor.HairStyle = "光头";
            }
    
            public override void BuildSex()
            {
                actor.Sex = "";
            }
    
            public override void BuildType()
            {
                actor.Type = "恶魔";
            }
        }
    
        /// <summary>
        /// 英雄建造器 : 具体建造者
        /// </summary>
        public class HeroBuilder : ActorBuilder
        {
            public override void BuildCostume()
            {
                actor.Costume = "盔甲";
            }
    
            public override void BuildFace()
            {
                actor.Face = "英俊";
            }
    
            public override void BuildHairStyle()
            {
                actor.HairStyle = "飘逸";
            }
    
            public override void BuildSex()
            {
                actor.Sex = "";
            }
    
            public override void BuildType()
            {
                actor.Type = "英雄";
            }
        }

      (4)ActorController:指挥者

        /// <summary>
        /// 游戏角色创建控制器:指挥者(Director)
        /// </summary>
        public class ActorController
        {
            /// <summary>
            /// 逐步构建复杂产品对象
            /// </summary>
            public Actor Construct(ActorBuilder builder)
            {
                builder.BuildType();
                builder.BuildSex();
                builder.BuildFace();
                builder.BuildCostume();
                builder.BuildHairStyle();
    
                return builder.CreateActor(); ;
            }
        }

      (5)客户端测试

        public class Client
        {
            public static void Main(string[] args)
            {
                ActorBuilder builder = (ActorBuilder)AppConfigHelper.GetConcreteBuilderInstance();
                ActorController director = new ActorController();
                Actor actor = director.Construct(builder);
    
                Console.WriteLine("角色类型:{0}", actor.Type);
                Console.WriteLine("角色性别:{0}", actor.Sex);
                Console.WriteLine("角色面容:{0}", actor.Face);
                Console.WriteLine("角色服装:{0}", actor.Costume);
                Console.WriteLine("角色发型:{0}", actor.HairStyle);
    
                Console.ReadKey();
            }
        }

      这里仍然采用了基于配置文件的方式:将具体的构建者配置在XML文件中,如需要更改只需要更改一下配置文件即可。

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="ConcreteBuilder" value="Manulife.ChengDu.DesignPattern.Builder.HeroBuilder, Manulife.ChengDu.DesignPattern.Builder" />
      </appSettings>
    </configuration>

      其中AppConfigHelper类的代码如下:

        public class AppConfigHelper
        {
            public static string GetConcreteBuilderName()
            {
                string factoryName = null;
                try
                {
                    factoryName = System.Configuration.ConfigurationManager.AppSettings["ConcreteBuilder"];
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                return factoryName;
            }
    
            public static object GetConcreteBuilderInstance()
            {
                string assemblyName = AppConfigHelper.GetConcreteBuilderName();
                Type type = Type.GetType(assemblyName);
    
                var instance = Activator.CreateInstance(type);
                return instance;
            }
        }
    View Code

      调试运行结果如下:

      

      此时如果我们需要构建一个恶魔角色,那么修改一下配置文件:

    <add key="ConcreteBuilder" value="Manulife.ChengDu.DesignPattern.Builder.DevilBuilder, Manulife.ChengDu.DesignPattern.Builder" />

      再次运行结果如下:

      

    四、建造者模式小结

    4.1 主要优点

      (1)客户端不需要知道产品内部的组成细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

      (2)具体建造者相对独立,增加新的具体建造者无需修改原有类库的代码,系统扩展比较方便,符合开闭原则。

      (3)可以更加精细地控制产品的创建过程 -> 将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

    4.2 主要缺点

      (1)对于所创建的产品有一定限制:一般这些产品都具有一些较多的共同点,其组成部分相似。如果差异性很大,那么则不适合使用建造者模式。

      (2)如果产品的内部结构复杂多变,可能会需要定义很多具体构建者来实现这些变化,会导致系统变得庞大,增加系统的理解难度和运行成本。

    4.3 应用场景

      (1)需要生成的产品对象由复杂的内部结构,这些产品对象通常包含多个成员变量。

      (2)需要生成的产品对象的属性相互依赖,需要指定其生成顺序。

      (3)隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

    参考资料

          DesignPattern

      刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

  • 相关阅读:
    改进初学者的PID-微分冲击
    孤独
    改进初学者的PID-采样时间
    mac10.9下eclipse的storm开发环境搭建
    ubuntu12.04+hadoop2.2.0+zookeeper3.4.5+hbase0.96.2+hive0.13.1伪分布式环境部署
    Linux学习笔记之rpm包管理功能全解
    Linux学习笔记之文件读取过程
    Linux学习笔记之Linux系统的swap分区
    Linux学习笔记之grep命令和使用正则表达式
    Prometheus监控学习笔记之容器监控Grafana模块
  • 原文地址:https://www.cnblogs.com/edisonchou/p/6828436.html
Copyright © 2011-2022 走看看