[工作中的设计模式]建造者模式builder

一、模式解析

  建造模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心。

  以上是对建造者模式的官方定义,简单说就是对于复杂对象的创建,由一个建造者封装了对象组件的生成,由专门的指挥者来负责指挥对象生产和组件装配,调用者仅需要通知指挥者建造者进行生产,即可从对象本身获取完整对象。

  要点为:

  1、 模式的主要参与者为:抽象建造者,具体建造者,指挥者。

  2、具体建造者负责具体实施生产

  3、指挥者仅负责提供解决方案和流程

  4、最终的产品创建细节和产品交付由具体建造者负责

二、模式代码

定义产品的模块组成

package build.patten;

/**
 * 产品的组成部分
 * @author zjl
 * @time 2016-1-29
 *
 */
public class Part {
    public String name;

    public Part(String name) {
        super();
        this.name = name;
    }
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return this.name.toString();
    }
}

2、定义产品,产品由三个部分组成,因此保存一个组成部分的列表

package build.patten;

import java.util.ArrayList;
import java.util.List;

/**
 * 产品,可以包含A,B,C三个部分
 * @author zjl
 * @time 2016-1-29
 *
 */
public class Product {
    List<Part> parts=new ArrayList<Part>();
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return parts.toString();
    }
    
}

3、抽象的建造者,规定了对产品各部分的建造接口

package build.patten;

public interface IBuild {
    public void buildPartA();
    public void buildPartB();
    public void buildPartC();
    public Product getResult();
}

4、具体建造者,实现抽象建造者的方法,可以有一个或多个

package build.patten;

public class ConcreteBuild implements IBuild {
    Product product=new Product();

    @Override
    public void buildPartA() {
        // TODO Auto-generated method stub
        product.parts.add(new Part("partA"));
    }

    @Override
    public void buildPartB() {
        // TODO Auto-generated method stub
        product.parts.add(new Part("partB"));
    }

    @Override
    public void buildPartC() {
        // TODO Auto-generated method stub
        product.parts.add(new Part("partC"));
    }

    @Override
    public Product getResult() {
        // TODO Auto-generated method stub
        return product;
    }

}

4、指挥者类,负责告诉建造者,应该以什么样的逻辑完成产品的创建

package build.patten;

public class Director {
    IBuild build;
    public Director(IBuild build){
        this.build=build;
    }
    
    public void build(){
        this.build.buildPartA();
        this.build.buildPartB();
        this.build.buildPartC();
    }
}

5、客户端

package build.patten;

public class Client {
    public static void main(String[] args) {
        IBuild build=new ConcreteBuild();
        Director director=new Director(build);
        director.build();
        Product product=build.getResult();
        System.out.println(product);
    }
    
}

6、运行结果,也就是创建的产品

[partA, partB, partC]

三、应用场景

建造者模式由于需要中间的指挥者来完成对产品各部分的建设,其实在工作中用的还是比较少,不过最近正在装修,似乎可以找到类似的原型:

在装修的过程中,我们将房子交给装修公司后,由设计师和工人来共同完成对房子的装修,其中设计师负责进行设计,规定房子如何装;具体干活:比如泥工,木工,电工均由工人完成。

整个装修过程比较复杂,因此我们选取简单的一块,比如门的设计和安装来举例:我的房子是两室一厨一卫,所以共需要四个门,门的牌子和材质可以有不同的选择,设计师负责进行选择,工人仅需要安装即可。

四、场景代码

1、定义门,

package build.example;

public class Door {
    //名称
    public String name;
    //材料
    public String type;
    //位置
    public String pos;
    public Door(String name,String pos){
        this.name=name;
        this.pos=pos;
    }
    
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return pos+"的位置安装厂家为"+name+"的"+type+"门";
    }

}

定义房子,也就是最终交付的成果

package build.example;

import java.util.ArrayList;
import java.util.List;

/**
 * 房子装修,可以请装修工人对房子进行装修
 * 不同人的房子可能装法不同
 * 假设装修两室一厅,共四个门,厨卫+两个卧室
 * @author zjl
 * @time 2016-1-29
 *
 */
public class House {
    List<Door> doors=new ArrayList<Door>();
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return doors.toString();
    }
}

3、定义工人,工人会装木门,也会装合金门

package build.example;
/**
 * 抽象的装修工人,定义了装修工人会的技能
 * 此处仅以装门来考虑
 * @author zjl
 * @time 2016-1-29
 *
 */
public abstract class AbstractWorker {

    public abstract void fixMumen(Door door);
    public abstract void fixHejinmen(Door door);
    public abstract House getHouse();
    
}

4、定义一个具体的工人,每个工人手艺不一样,所以可以选择的工人很多,但他们都必须会装门

package build.example;

public class ConcreteWorkerA extends AbstractWorker {
    public House house=new House();
    @Override
    public House getHouse(){
        return house;
    }
    @Override
    public void fixMumen(Door door) {
        door.type="木";
        house.doors.add(door);
        
    }

    @Override
    public void fixHejinmen(Door door) {
        door.type="合金";
        house.doors.add(door);
    }

}

5、设计师,负责设计门如何安装

package build.example;
/**
 * 设计师,负责设计门的的种类和选材
 * @author zjl
 * @time 2016-1-29
 *
 */
public class Designer {
    AbstractWorker worker;
    public Designer(AbstractWorker worker){
        this.worker=worker;
    }
    public void bulid() {
        worker.fixMumen(new Door("A厂家", "厨房"));
        worker.fixMumen(new Door("A厂家", "厕所"));
        worker.fixHejinmen(new Door("A厂家", "主卧"));
        worker.fixHejinmen(new Door("A厂家", "次卧"));
    }

}

6、我自己,只负责催进度和要结果

package build.example;

public class Client {
    public static void main(String[] args) {
        AbstractWorker worker=new ConcreteWorkerA();
        Designer designer=new Designer(worker);
        designer.bulid();
        House house=worker.getHouse();
        System.out.println(house);
    }
}

7、生产结果

[厨房的位置安装厂家为A厂家的木门, 
厕所的位置安装厂家为A厂家的木门,
主卧的位置安装厂家为A厂家的合金门,
次卧的位置安装厂家为A厂家的合金门]

五、模式疑问

  1、产品的交付,在模式标准中有建造者进行完成,似乎感觉由指挥者直接完成整个产品的返回似乎也可以,具体区别以后补充

  2、指挥者的存在是建造者模式的关键,将顺序剥离了建造者,其实我们完全可以将建造顺序和过程封装到抽象建造者内,此时建造者模式就变成了模板模式。

  3、针对第二点,为什么有了原型模式后,还会有建造者模式,其实建造者模式可以有多个指挥者,不同的指挥者可以设计出不同的建造顺序和逻辑,从而产生出不同的产品,例如我们装修时,找不同的设计师,设计出不同的风格,那么用的材料和牌子也会不同,此时原型模式由于在父类中规定了建造流程,反而无法达到此效果。

原文地址:https://www.cnblogs.com/jyyzzjl/p/5174203.html