.Net设计模式之建造者模式(Builder Pattern)

1.意图

建造者模式的核心思想是将一个"复杂对象的构建算法"与它的"部件及组装方式"分离,使得构件算法和组装方式可以独立应对变化;

复用同样的构建算法可以创建不同的表示,不同的构建过程可以复用相同的部件组装方式。

2.示意性代码解析

在建造者模式中,有如下四个角色:

     Product产品类:

通常是实现了模板方法模式,也就是有模板方法和基本方法。

     Builder抽象建造者:

规范产品的组建,一般是由子类实现。

     ConcreteBuilder具体建造者

实现抽象类定义的所有方法,并返回一个组件好的对象。

     Director导演

负责安排已有模块的顺序,然后告诉Builder开始创建。

代码清单:   

复制代码
public class Product
    {
        IList<string> parts = new List<string>();
        public void Add(string str)
        {
            parts.Add(str);
        }

        public void Show()
        {
            Console.WriteLine("\n产品创建-----");
            foreach (string item in parts)
            {
                Console.WriteLine(item);
            }
        }
    }

    public abstract class Builder
    {
        public abstract void BuilderPartA();
        public abstract void BuilderPartB();
        public abstract Product GetResult();
    }

    class ConcreteBuilder1 : Builder
    {
        private Product product = new Product();

        public override void BuilderPartA()
        {
            product.Add("部件A");
        }

        public override void BuilderPartB()
        {
            product.Add("部件B");
        }

        public override Product GetResult()
        {
            return product;
        }
    }


    public class ConcerteBulider2 : Builder
    {
        private Product product = new Product();

        public override void BuilderPartA()
        {
            product.Add("部件X");
        }

        public override void BuilderPartB()
        {
            product.Add("部件Y");
        }

        public override Product GetResult()
        {
            return product;
        }
    }

    public class Director
    {
        public void Construct(Builder builder)
        {
            builder.BuilderPartA();
            builder.BuilderPartB();
        }
    }
复制代码
复制代码
 static void Main(string[] args)
        {
            Director director = new Director();
            Builder b1 = new ConcreteBuilder1();
            Builder b2 = new ConcerteBulider2();
            director.Construct(b1);
            Product p1 = b1.GetResult();
            p1.Show();
            director.Construct(b2);
            Product p2 = b2.GetResult();
            p2.Show();
        }
复制代码

 总结:建造者模式的实质是解耦组装过程和创建具体部件,使得我们不关心每个部件是如何组装的。

          建造者模式的奥妙在于Builder将构建次序交给Director类按照次序构建所需的组件。

相关模式

          抽象工厂:重点是工厂模式(简单或者复杂工厂),而建造者模式重点是由简单模式构建复杂对象。

          复合模式:经常被用来构建复杂模式。

建造模式与抽象工厂模式的比较

两者都是用来创建同事属于几个产品族的对象的模式。

在抽象工厂模式中,每一次工厂对象被调用时都会返回一个完整的产品对象,而客户端有可能会决定把这些产品组装成一个更大更复杂的产品,也有可能不会。建造类则不同,它一点一点地建造出一个复杂的产品,而这个产品的组装过程就发送在建造者角色内部。建造者模式的客户端拿到的是一个完整的最后产品。虽说两者都是设计模式,但是抽象工厂模式处在更加具体的尺度上,而建造者模式则处于更加宏观的尺度上。

比如众神造人:女娲利用建造模式负责把灵魂、耳目、手臂等组合成一个完整的人,而黄帝、上骈、桑林各自利用工厂模式创造出灵魂耳目手臂等。女娲不必考虑灵魂耳目手臂是什么样子,怎么创造出来的。

建造模式与策略模式:建造模式是策略模式的一种特殊情况。这两种模式的不同在于他们的用意不同。建造模式适用于为客户端一点一点地建造出新的对象,而不同类型的具体建造者角色虽然拥有相同的接口,但是它们所创造的出来的对象可能完全不同。

策略模式的目的是为了算法提供抽象的接口,换言之。一个具体策略类把一个算法包装到一个对象里面,而不同的具体策略对象为一种一般性的服务提供不同的实现。

在以下情况下应当使用建造模式:

1、需要生成的产品对象有复杂的的内部结构,每个内部成分本身可能是对象,也可以是一个对象的组成部分。

2.需要生产的产品对象的属性相互依赖,建造模式可以强制实行一种分步骤进行的建造过程,因此如果产品对象的一个属性必须在另一个属性被赋值之后才可以被赋值使用建造者模式是一个很好的设计思想。

下面摘自另外一个例子:

好吧,我承认上面那句话是Baidu来的,要是能很容易的明白讲的是什么,请切换到漫游模式继续漫游吧。
下面我们不聊这些模式了,继续聊我们的实验室,因为模式不发给我们工资,实验室才是发工资的。
最近我们的实验室又遇到麻烦了,老总们即使能够同时使用女秘书了也忍不住发火了,因为赶太阳国一大笔兽人订单,到交付的时候才发现,大都数兽人没有头,没有头的兽人能叫兽人吗?那只能叫无头兽!

复制代码
class ShouRen {
    private String head;
    private String body;
    private String foot;

    public void setHead(String head) {
        this.head = head;
    }
    public void setBody(String body) {
        this.body = body;
    }
    public void setFoot(String foot) {
        this.foot = foot;
    }
}

public class Builder {
    public static void main(String[] args) {
        ShouRen sr = new ShouRen();
        sr.setBody("兽身");
        sr.setFoot("兽脚");
    }
}
复制代码

为了解决这种浪费材料的问题再次发生,我们实验室又开了大会,某位管理层说这是因为兽人分厂建设在太阳国的原因,当地的土著完全不理解我们兽人工厂生产兽人时的步骤,所以才会有这个问题,所以要加大兽人员工的培训,让他们的技能和我们人类工厂的员工达到一致水平。老总们一听,立即暴怒,不说培训兽人员工的费用问题(其实就是我们coding时了解其他类的接口花费的时间),就兽人的智商,即使培训了也不一定有效果(coding时面对一个上千行的类,实在是提不起兴致过一遍 -_-! )。

这时有是我们的资深顾问说,既然这样,我们就不要让员工自己创建兽人了,我们给他们发一个兽人创建器,他们只要把原料放到创建器里面自动就出来一个兽人好了。

复制代码
class ShouRen {
    private String head;
    private String body;
    private String foot;

    public void setHead(String head) {
        this.head = head;
    }
    public void setBody(String body) {
        this.body = body;
    }
    public void setFoot(String foot) {
        this.foot = foot;
    }
}

class ShouRenBuilder {
    ShouRen sr;
    
    public ShouRenBuilder (){
        sr = new ShouRen();
    }
    public void createHead() {
        sr.setHead("兽头");
    }
    public void createBody() {
        sr.setBody("兽身");
    }
    public void createFoot() {
        sr.setFoot("兽脚");
    }
    public ShouRen createShouRen() {
        createHead();
        createBody();
        createFoot();
        return sr;
    }
}

public class Builder {
    public static void main(String[] args) {
        ShouRen sr = new ShouRenBuilder().createShouRen();
    }
}
复制代码

老总一看这个方法不错,大肆赞赏,并且希望扩大使用范围,希望我们的正常人工厂和人妖工厂也使用这种构造器。

复制代码
class Ren {

}

class NanRen extends Ren {

    private String head;
    private String body;
    private String foot;

    public void setHead(String head) {
        this.head = head;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public void setFoot(String foot) {
        this.foot = foot;
    }

}

class NvRen extends Ren {

    private String head;
    private String body;
    private String foot;

    public void setHead(String head) {
        this.head = head;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public void setFoot(String foot) {
        this.foot = foot;
    }

}

class RenYao extends Ren {

    private String head;
    private String body;
    private String foot;

    public void setHead(String head) {
        this.head = head;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public void setFoot(String foot) {
        this.foot = foot;
    }

}

class ShouRen extends Ren {

    private String head;
    private String body;
    private String foot;

    public void setHead(String head) {
        this.head = head;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public void setFoot(String foot) {
        this.foot = foot;
    }

}

class NanRenBuilder {
    NanRen nr;
    
    public NanRenBuilder (){
        nr = new NanRen();
    }
    public void createHead() {
        nr.setHead("男人头");
    }
    public void createBody() {
        nr.setBody("男人身");
    }
    public void createFoot() {
        nr.setFoot("男人脚");
    }
    public NanRen createNanRen() {
        createHead();
        createBody();
        createFoot();
        return nr;
    }
}

class NvRenBuilder {
    NvRen nr;
    
    public NvRenBuilder (){
        nr = new NvRen();
    }
    public void createHead() {
        nr.setHead("女人头");
    }
    public void createBody() {
        nr.setBody("女人身");
    }
    public void createFoot() {
        nr.setFoot("女人脚");
    }
    public NvRen createNvRen() {
        createHead();
        createBody();
        createFoot();
        return nr;
    }
}
class RenYaoBuilder {
    RenYao ry;
    
    public RenYaoBuilder (){
        ry = new RenYao();
    }
    public void createHead() {
        ry.setHead("人妖头");
    }
    public void createBody() {
        ry.setBody("人妖身");
    }
    public void createFoot() {
        ry.setFoot("人妖脚");
    }
    public RenYao createRenYao() {
        createHead();
        createBody();
        createFoot();
        return ry;
    }
}
class ShouRenBuilder {
    ShouRen sr;
    
    public ShouRenBuilder (){
        sr = new ShouRen();
    }
    public void createHead() {
        sr.setHead("兽头");
    }
    public void createBody() {
        sr.setBody("兽身");
    }
    public void createFoot() {
        sr.setFoot("兽脚");
    }
    public ShouRen createShouRen() {
        createHead();
        createBody();
        createFoot();
        return sr;
    }
}
复制代码

这时财务科的人发表意见了,如果我们的各大工厂都使用构造器的话,确实能省下不少工人的培训费用,但是硬件成本会加大不少阿(即重复代码),并且提出,我们的生产流程是一样的,都是先创建头,再创建身体,最后创建脚。

所以我们把组装的工作弄出一个组装器,然后要生产不同的人的时候仿佛不同的构造器,那么我们原先放在构造器中的组装步骤就能够重用了。于是我们就不知不觉的用上了建造者模式来生产。

public abstract class Ren
{
    public abstract void setHead(string head);
    public abstract void setBody(string body);
    public abstract void setFoot(string foot);
}

public class NanRen :Ren 
{

    private string head;
    private string body;
    private string foot;

    public override  void setHead(string head) {
        this.head = head;
    }

    public override void setBody(string body) {
        this.body = body;
    }

    public override void setFoot(string foot) {
        this.foot = foot;
    }

}

public class NvRen :Ren 
{

    private string head;
    private string body;
    private string foot;

    public override  void setHead(string head)
    {
        this.head = head;
    }

    public override void setBody(string body) 
    {
        this.body = body;
    }

    public override void setFoot(string foot)
    {
        this.foot = foot;
    }

}

public class RenYao : Ren
 {

    private string head;
    private string body;
    private string foot;

    public override  void setHead(string head)
    {
        this.head = head;
    }

    public override void setBody(string body)
    {
        this.body = body;
    }

    public override void setFoot(string foot)
    {
        this.foot = foot;
    }

}

public class ShouRen :Ren
 {

    private string head;
    private string body;
    private string foot;

    public override  void setHead(string head)
    {
        this.head = head;
    }

    public override void setBody(string body) 
    {
        this.body = body;
    }

    public override void setFoot(string foot)
    {
        this.foot = foot;
    }

}

public abstract class RenBuilder 
{
    public abstract void createHead();
    public abstract void createBody();
    public abstract void createFoot();
    public abstract Ren getRen();
}

public class NanRenBuilder :RenBuilder
{
    NanRen nr;
    
    public NanRenBuilder ()
    {
        nr = new NanRen();
    }
    public void createHead()
    {
        nr.setHead("男人头");
    }
    public void createBody()
    {
        nr.setBody("男人身");
    }
    public void createFoot() 
    {
        nr.setFoot("男人脚");
    }
    public Ren getRen()
    {
        return nr;
    }
}

class NvRenBuilder :RenBuilder
{
    NvRen nr;
    
    public NvRenBuilder ()
    {
        nr = new NvRen();
    }
    public void createHead()
    {
        nr.setHead("女人头");
    }
    public void createBody()
    {
        nr.setBody("女人身");
    }
    public void createFoot()
    {
        nr.setFoot("女人脚");
    }
    public Ren getRen() 
    {
        return nr;
    }
}
class RenYaoBuilder :RenBuilder
{
    RenYao ry;
    
    public RenYaoBuilder ()
    {
        ry = new RenYao();
    }
    public void createHead() 
    {
        ry.setHead("人妖头");
    }
    public void createBody() 
    {
        ry.setBody("人妖身");
    }
    public void createFoot() 
    {
        ry.setFoot("人妖脚");
    }
    public Ren getRen()
    {
        return ry;
    }
}
class ShouRenBuilder :RenBuilder
{
    ShouRen sr;
    
    public ShouRenBuilder ()
    {
        sr = new ShouRen();
    }
    public void createHead() 
    {
        sr.setHead("兽头");
    }
    public void createBody() 
    {
        sr.setBody("兽身");
    }
    public void createFoot()
   {
        sr.setFoot("兽脚");
    }
    public Ren getRen()
   {
        return sr;
    }
}

class RenDirector
{
    public Ren create(RenBuilder builder) 
    {
        builder.createHead();
        builder.createBody();
        builder.createFoot();
        return builder.getRen();
    }
}

public class Builder 
{
    public static void main(string[] args) 
    {
        
        ShouRenBuilder srBuilder = new ShouRenBuilder();//兽人建造核心
        NanRenBuilder nanrBuilder = new NanRenBuilder();//男人建造核心
        NvRenBuilder nvrBuilder = new NvRenBuilder();//女人建造核心
        RenYaoBuilder ryBuilder = new RenYaoBuilder();//人妖建造核心
        
        RenDirector rd = new RenDirector();//只有一个组装器,装上不同的建造核心,就能建出不同的人。
        Ren sr = rd.create(srBuilder);
        Ren nanren = rd.create(nanrBuilder);
        Ren nvren = rd.create(nvrBuilder);
        Ren ry = rd.create(ryBuilder);
        
    }
}

参考与来源:

设计模式笔记之五 (建造者模式):http://www.cnblogs.com/biglaojiang/archive/2013/05/13/3075211.html

.NET设计模式(4):建造者模式(Builder Pattern):http://terrylee.cnblogs.com/archive/2005/12/19/299878.html

原文地址:https://www.cnblogs.com/8090sns/p/BuilderPattern.html