【设计模式】建造者模式 Builder Pattern

前面学习了简单工厂模式工厂方法模式以及抽象工厂模式,这些都是建立类的对象所使用的一些经常使用的方法和套路, 那么若是咱们建立一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去作”,23设计模式总有一个模式是适合这种复杂对象的建立。好比如今的智能手机组成, 它包括一个屏幕,摄像头,耳机接口,USB接口,CPU, RAM,主板等等, 可是每个型号的手机的屏幕又不同,有的是刘海的,有的是全屏的,有的是全面屏的,CUP 也不同,有骁龙820 的,有 660的还有麒麟920 的等等,手机的组成图以下:html

image_thumb4

image_thumb6

 

那么要建立一个这样的复杂对象, 该怎么建立呢? 那么该建造者模式闪亮登场了。编程

1、建造者模式定义

建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示。建造者模式是一种对象建立型模式。设计模式

2、建造者模式结构图

 image_thumb18

一、AbstractBuilder(抽象建造者):

它为建立一个产品Product对象的各个部件指定抽象接口,在该接口中通常声明两类方法,一类方法是buildPartX(),它们用于建立复杂对象的各个部件;另外一类方法是GetResult(),它们用于返回复杂对象。AbstractBuilder既能够是抽象类,也能够是接口。app

二、ConcreteBuilder(具体建造者):

它实现了AbstractBuilder接口,实现各个部件的具体构造和装配方法,定义并明确它所建立的复杂对象,也能够提供一个方法返回建立好的复杂产品对象。ide

三、Product(产品角色):

它是被构建的复杂对象,包含多个组成部件,具体建造者建立该产品的内部表示并定义它的装配过程。函数

四、Director(导演):

负责安排复杂对象的建造次序,导演与抽象建造者之间存在关联关系,能够在其Construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端通常只须要与指挥者进行交互,在客户端肯定具体建造者的类型,并实例化具体建造者对象(也能够经过配置文件和反射机制),而后经过指挥者类的构造函数将该对象传入指挥者类中。学习

3、建造者模式典型代码结构

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

public abstract class AbstractBuilder
{
    protected Product product = new Product();
    public abstract void BuildPartA();
    public abstract void BuildPartB();
    public abstract void BuildPartC();
    public  Product GetResult()
    {          
        return product;
    }
}

public class ConreteBuilder : AbstractBuilder
{
    public override void BuildPartA()
    {
        this.product.PartA = "PartA";
    }

    public override void BuildPartB()
    {
        this.product.PartB = "PartB";
    }

    public override void BuildPartC()
    {
        this.product.PartC = "PartC";
    }   
}

public class Director
{
    private AbstractBuilder builder;
    public Director(AbstractBuilder builder)
    {
        this.builder = builder;
    }

    public Product Construct()
    {
        builder.BuildPartA();
        builder.BuildPartB();
        builder.BuildPartC();
        return builder.GetResult();
    }
}

客户端调用:ui

static void Main(string[] args)
{
    AbstractBuilder builder = new ConreteBuilder();
    Director director = new Director(builder);
    Product product = director.Construct();

    Console.WriteLine(product.PartA);
    Console.WriteLine(product.PartB);
    Console.WriteLine(product.PartC);

    Console.ReadKey();
}

输出结果:this

image_thumb12[4]

4、建造者模式实例

咱们用本文开头提出的手组成的例子来挑选几个核心部件来构造几个型号的手机,使用建造者模式。spa

一、X1型手机:CUP 骁龙 835, RAM 6GB ,屏幕 刘海全屏, 硬盘 64GB。

二、X2 型手机: CUP 麒麟 930, RAM 8G, 屏幕 全面屏, 硬盘 128GB。

三、X3型手机: CPU  骁龙 960 RAM 10G,屏幕 超清全面屏 256GB。

UML 图以下:

image_thumb34

代码:

public class Mobile
{
    public string CPU { get; set; }
    public string Screen { get; set; }
    public string RAM { get; set; }
    public string Disk { get; set; }
}
public abstract class MobileBuilder
{
    protected Mobile mobile = new Mobile();
    public abstract void BuildCPU();
    public abstract void BuildScreen();
    public abstract void BuildRAM();
    public abstract void BuildDisk();
    public Mobile GetMobile()
    {
        return this.mobile;
    }
}

public class X1Builder:MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X1]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X1]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X1]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X1]:Disk had been built.";
    }
}

public class X2Builder:MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X2]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X2]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X2]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X2]:Disk had been built.";
    }
}

public class X3Builder:MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X3]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X3]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X3]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X3]:Disk had been built.";
    }
}

public class MobileDirector
{
    private MobileBuilder builder;
    public MobileDirector(MobileBuilder builder)
    {
      this.builder=builder;
    }

    public Mobile GetMobile(){
     this.builder.BuildCPU();
     this.builder.BuildRAM();
     this.builder.BuildScreen();
     this.builder.BuildDisk();
     return this.builder.GetMobile();
    }
}

调用代码以下:

static void Main(string[] args)
{
    MobileBuilder builder=new X1Builder();
    MobileDirector mobileDrector = new MobileDirector(builder);
    Mobile mobile = mobileDrector.GetMobile();
    Console.WriteLine(mobile.CPU);
    Console.WriteLine(mobile.Screen);
    Console.WriteLine(mobile.RAM);
    Console.WriteLine(mobile.Disk);
    Console.ReadKey();
}

输出结果:

image_thumb20 

若是想生产X2型号的手机,只须要将具体建造者代码修改一下就能够了,即将下面的一行代码:

MobileBuilder builder=new X1Builder();

改为:

MobileBuilder builder=new X2Builder();

输出结果:

image_thumb22

也能够将具体建造者类配置在配置文件中,经过反射来建立建造者对象进而建立出新的型号的手机。

在配置文件中加入以下配置:

<appSettings>
    <add key="Builder" value="DesignPattern.Builder.MobileInstance.X3Builder"/>
</appSettings>

客户端调用代码以下:

static void Main(string[] args)
{
    MobileBuilder builder;
    var setting = ConfigurationSettings.AppSettings["Builder"];
    var obj = Type.GetType(setting);
    if (obj == null) return;
    builder = Activator.CreateInstance(obj) as MobileBuilder;

    if (builder == null) return;
    
    MobileDirector mobileDrector = new MobileDirector(builder);
    Mobile mobile = mobileDrector.GetMobile();
    Console.WriteLine(mobile.CPU);
    Console.WriteLine(mobile.Screen);
    Console.WriteLine(mobile.RAM);
    Console.WriteLine(mobile.Disk);
    Console.ReadKey();
}

输出结果:

image_thumb24

 

5、建造者模式的优势

  1. 在建造者模式中,客户端没必要知道产品内部组成的细节,将产品自己与产品的建立过程解耦,使得相同的建立过程能够建立不一样的产品对象。
  2. 每个具体建造者都相对独立,而与其余的具体建造者无关,所以能够很方便地替换具体建造者或增长新的具体建造者,用户使用不一样的具体建造者便可获得不一样的产品对象。因为指挥者类针对抽象建造者编程,增长新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则(OCP)
  3. 能够更加精细地控制产品的建立过程。将复杂产品的建立步骤分解在不一样的方法中,使得建立过程更加清晰,也更方便使用程序来控制建立过程

6、建造者模式的缺点

  1. 建造者模式所建立的产品通常具备较多的共同点,其组成部分类似,若是产品之间的差别性很大,例如不少组成部分都不相同,不适合使用建造者模式,所以其使用范围受到必定的限制。
  2. 若是产品的内部变化复杂,可能会致使须要定义不少具体建造者类来实现这种变化,致使系统变得很庞大,增长系统的理解难度和运行成本。

7、建造者模式的使用场景

  1. 须要生成的产品对象有复杂的内部结构,这些产品对象一般包含多个成员属性。
  2. 须要生成的产品对象的属性相互依赖,须要指定其生成顺序。
  3. 对象的建立过程独立于建立该对象的类。在建造者模式中经过引入了指挥者类,将建立过程封装在指挥者类中,而不在建造者类和客户类中。
  4. 隔离复杂对象的建立和使用,并使得相同的建立过程能够建立不一样的产品。

8、扩展 

Director在建造者模式中扮演着重要的角色,Director类看似简单可是做用却很是大,它决定复杂对象各个部分的建立顺序而且将构建对象的过程和具体建造者隔离,好比建立一个房子,首先确定要作的事情是打地基,而后是磊墙,而后是封顶,最后是装修,这个过程是有顺序的且必须是这个顺序,其它过程不没法完成房子的建造。

Director'就好像是拍电影导演同样,导演要拍一部电影,须要拍摄若干影像片断,最后由剪辑师作剪接拼接,导演最后会进行最终的剪辑排版合成一个长片-- 电影。那么电影就充当了建造者模式中的复杂产品,拍摄的影像片断就是产片的各个部分,剪辑就是建造者模式的具体具体建造者,剧本是建造者模式的抽象建造者,导演就是Director。那么在在这个过程当中,编剧是不能够兼任导演? 剪辑师是否是也能够兼任导演呢?答案是确定的。

1.抽象建造者干了Director的活

那上面手机建造的实例,删除掉Diretor, 将建立复杂对象的逻辑放到抽象建造者中,而且使子类方法不能重写父类中的建造产品的方法,引用以前的配置代码演变成以下:

public class Mobile
{
    public string CPU { get; set; }
    public string Screen { get; set; }
    public string RAM { get; set; }
    public string Disk { get; set; }
}
public abstract class MobileBuilder
{
    protected Mobile mobile = new Mobile();
    public abstract void BuildCPU();
    public abstract void BuildScreen();
    public abstract void BuildRAM();
    public abstract void BuildDisk();
    public static Mobile GetMobile(MobileBuilder builder)
    {
        builder.BuildCPU();
        builder.BuildScreen();
        builder.BuildRAM();
        builder.BuildDisk();
        return builder.mobile;
    }
}

public class X1Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X1]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X1]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X1]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X1]:Disk had been built.";
    }
}

public class X2Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X2]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X2]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X2]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X2]:Disk had been built.";
    }
}

public class X3Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X3]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X3]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X3]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X3]:Disk had been built.";
    }
}

调用代码:

static void Main(string[] args)
{
    MobileBuilder builder;
    var setting = ConfigurationSettings.AppSettings["Builder"];
    var obj = Type.GetType(setting);
    if (obj == null) return;
    builder = Activator.CreateInstance(obj) as MobileBuilder;

    if (builder == null) return;

    Mobile mobile = builder.GetMobile();
    Console.WriteLine(mobile.CPU);
    Console.WriteLine(mobile.Screen);
    Console.WriteLine(mobile.RAM);
    Console.WriteLine(mobile.Disk);
    Console.ReadKey();
}

输出结果:

image_thumb26

这种在抽象建造者中使用了一个静态方法来建立产品的作法的好处是产品建立出来的一致性很好,建立产品流程被统一封装,通常不会有差别,这种方式抽象类控制了产品建造的顺序,而且全部的产品的建立顺序都不能改变了(如造房子的流程),对于要求建立顺序一致,而且产品部件的建立都路程一致的产品来讲这是一个优势。

可是若是想建立出来的产品有差别,每个产品的顺序都不同那该怎么办呢?好比如今这种方法建立出来的顺序是: CPU=》Screen=》RAM=》Disk, 那么我要想X3型号的手机建立顺序变成:CPU=》RAM=》Disk=》Screen。 这种方法就显得不灵活了,没有办法作到个性化了。处理典型的将建造过程的控制权交给Director外,还能够不用Director来完成吗?

二、具体建造者和抽象建造者均可以干Director的活

这里咱们依然删掉Director, 将抽象方法中的建立方法变成子类能够重写的虚方法就能够了,而后在具体建造者中重写抽象建造者的建立方法就能够了。

如今咱们建立X1,X2,X3型号的手机的顺序分别是这样的:

X1: CPU=》Screen=》RAM=》Disk

X2:CPU=》RAM=》Disk=》Screen

X3:CPU=》Disk=》RAM=》Screen

代码以下:

public class Mobile
{
    public string CPU { get; set; }
    public string Screen { get; set; }
    public string RAM { get; set; }
    public string Disk { get; set; }
}
public abstract class MobileBuilder
{
    protected Mobile mobile = new Mobile();
    public abstract void BuildCPU();
    public abstract void BuildScreen();
    public abstract void BuildRAM();
    public abstract void BuildDisk();
    public virtual Mobile GetMobile()
    {
        this.BuildCPU();
        this.BuildScreen();
        this.BuildRAM();
        this.BuildDisk();
        Console.WriteLine(mobile.CPU);
        Console.WriteLine(mobile.Screen);
        Console.WriteLine(mobile.RAM);
        Console.WriteLine(mobile.Disk);
       
        return this.mobile;
    }
}

public class X1Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X1]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X1]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X1]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X1]:Disk had been built.";
    }
}

public class X2Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X2]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X2]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X2]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X2]:Disk had been built.";
    }

    public override Mobile GetMobile()
    {
        BuildCPU();
        BuildRAM();
        BuildDisk();
        BuildScreen();
        Console.WriteLine(mobile.CPU);       
        Console.WriteLine(mobile.RAM);
        Console.WriteLine(mobile.Disk);
        Console.WriteLine(mobile.Screen);
        return this.mobile;
    }
}

public class X3Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X3]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X3]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X3]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X3]:Disk had been built.";
    }
    public override Mobile GetMobile()
    {
        BuildCPU();        
        BuildDisk();
        BuildRAM();
        BuildScreen();
        Console.WriteLine(mobile.CPU);
        Console.WriteLine(mobile.Disk);
        Console.WriteLine(mobile.RAM);       
        Console.WriteLine(mobile.Screen);
        return this.mobile;
    }
}

调用代码:

static void Main(string[] args)
{
    MobileBuilder builder;
    var setting = ConfigurationSettings.AppSettings["Builder"];
    var obj = Type.GetType(setting);
    if (obj == null) return;
    builder = Activator.CreateInstance(obj) as MobileBuilder;

    if (builder == null) return;

    Mobile mobile = builder.GetMobile();

    Console.ReadKey();
}

输出结果:

image_thumb28

3.  控制某些部件不用被建立

假如要造一个X4型号的手机,这个手机支持NFC,咱们知道X1,X2,X3中都不支持NFC,那怎么办呢?,咱们能够给抽象建造者类加一个方法,叫 HasNFC()而且返回bool值,并将其设置成默认值为false。 修改抽象建造者的GetMobile() 方法,只有当HasNFC()返回 true是才建立NFC模块,而且在X4Builder的具体建造者类中重写HasNFC()方法使其返回true就能够了。

代码以下:

public class Mobile
{
    public string CPU { get; set; }
    public string Screen { get; set; }
    public string RAM { get; set; }
    public string Disk { get; set; }
}
public abstract class MobileBuilder
{
    protected Mobile mobile = new Mobile();
    public abstract void BuildCPU();
    public abstract void BuildScreen();
    public abstract void BuildRAM();
    public abstract void BuildDisk();
    public virtual void BuildNFC()
    {
        Console.WriteLine("NFC had been built.");
    }
    protected virtual bool HasNFC()
    {
        return false;
    }
    public virtual Mobile GetMobile()
    {
        this.BuildCPU();
        this.BuildScreen();
        this.BuildRAM();
        this.BuildDisk();
        if(HasNFC())
        {
            this.BuildNFC();
        }
        Console.WriteLine(mobile.CPU);
        Console.WriteLine(mobile.Screen);
        Console.WriteLine(mobile.RAM);
        Console.WriteLine(mobile.Disk);
       
        return this.mobile;
    }
}

public class X1Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X1]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X1]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X1]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X1]:Disk had been built.";
    }
}

public class X2Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X2]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X2]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X2]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X2]:Disk had been built.";
    }

    public override Mobile GetMobile()
    {
        BuildCPU();
        BuildRAM();
        BuildDisk();
        BuildScreen();
        Console.WriteLine(mobile.CPU);       
        Console.WriteLine(mobile.RAM);
        Console.WriteLine(mobile.Disk);
        Console.WriteLine(mobile.Screen);
        return this.mobile;
    }
}

public class X3Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X3]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X3]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X3]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X3]:Disk had been built.";
    }
    public override Mobile GetMobile()
    {
        BuildCPU();        
        BuildDisk();
        BuildRAM();
        BuildScreen();
        Console.WriteLine(mobile.CPU);
        Console.WriteLine(mobile.Disk);
        Console.WriteLine(mobile.RAM);       
        Console.WriteLine(mobile.Screen);
        return this.mobile;
    }
}
public class X4Builder : MobileBuilder
{
    public override void BuildCPU()
    {
        mobile.CPU = "[X4]:CPU had been built.";
    }

    public override void BuildScreen()
    {
        mobile.Screen = "[X4]:Screen had been built.";
    }

    public override void BuildRAM()
    {
        mobile.RAM = "[X4]:RAM had been built.";
    }

    public override void BuildDisk()
    {
        mobile.Disk = "[X4]:Disk had been built.";
    }
    
    protected override bool HasNFC()
    {
 	     return true;
    }
}

App.Config 配置:

<appSettings>
    <add key="Builder" value="DesignPattern.Builder.MobileInstance.X3Builder"/>
</appSettings>

客户端代码:

static void Main(string[] args)
{
    MobileBuilder builder;
    
    var setting = ConfigurationSettings.AppSettings["Builder"];
    var obj = Type.GetType(setting);
    if (obj == null) return;
    builder = Activator.CreateInstance(obj) as MobileBuilder;

    if (builder == null) return;

    Mobile mobile = builder.GetMobile();

    Console.ReadKey();
}

输出结果:

image_thumb30

修改配置文件,使其造一台X4 以下,调用代码不变:

<appSettings>
    <add key="Builder" value="DesignPattern.Builder.MobileInstance.X4Builder"/>
</appSettings>

输出结果:

image_thumb32

好了建造者模式就探讨到这里。

相关文章
相关标签/搜索