如果一个对象由多个元素组成,而且这些元素可组成不同的对象,用构造者模式去分离出这个对象的构造过程。
构造者模式 Builder
问题
An application needs to create the elements of a complex aggregate. The specification for the aggregate exists on secondary storage and one of many representations needs to be built in primary storage.
意图:
- Separate the construction of a complex object from its representation so that the same construction process can create different representations.
 - Parse a complex representation, create one of several targets.
 
代码
例:比如一个网店卖包子=10块,饺子=20快,馒头=50块,很多用户一次买两样或三样都要点几次,于是使用构造者模式可以构造一个“套餐”,包子和饺子一走卖省5元,三个一起买省10元,除了方便用户,还带来了促销效果。
代码1:元数据
package com.xdnote.DesignPattern.creational.bulider;
public enum Product {
    PRODUCT1("包子",10),
    PRODUCT2("馒头",50),
    PRODUCT3("饺子",20);
    private String name;
    private int price;
    private Product(String name1,int price1){
        this.name=name1;
        this.price=price1;
    }
    public String getName(){
        return this.name;
    }
    public int getPirce(){
        return this.price;
    }
}
代码2:套餐类,用户买一个套餐就可知道套餐里面有什么内容
package com.xdnote.DesignPattern.creational.bulider;
import java.util.ArrayList;
import java.util.List;
public class Combo {
    //套餐包含的产品
    private List<Product> product ;
    //套餐折扣
    private int discount;
    public  Combo(){
        this.product=new ArrayList<Product>();
        this.discount=0;
    }
    public void setDiscount(int discount){
        this.discount = discount;
    }
    public void addProduct(Product p){
        this.product.add(p);
    }
    public String toString(){
        int length=product.size();
        StringBuffer sb=new StringBuffer("买了");
        int total = 0;
        for(int i=0;i<length;i++){
            Product p = product.get(i);
            total+=p.getPirce();
            sb.append(p.getName()).append(" ");
        }
        sb.append(length).append("件物品");
        sb.append("共").append(total).append("元");
        sb.append("套餐优惠").append(this.discount).append("元");
        sb.append("共").append(total-this.discount).append("元");
        return sb.toString();
    }
}
代码3:套餐构造类,及详细套餐的Bulider
package com.xdnote.DesignPattern.creational.bulider;
public abstract class ComboBulider {
    //每个套餐制造者们都有自己的套餐属性,按照套餐属性订做套餐
    private Combo combo;
    //给套餐加入套餐需要的内容
    public abstract void builder();
    //给套餐对应的套餐优惠
    public abstract void disCount();
    //开始制作套餐
    public void bulidCombo(){
        this.combo = new Combo(); 
        this.builder();
    }
    //取套餐
    public Combo getCombo(){
        return this.combo;
    }
    //套餐公用的方便代码
    public void addProduct(Product p){
        this.combo.addProduct(p);
    }
    public void setDiscount(int discount){
        this.combo.setDiscount(discount);
    }
}
public class Combo1Bulider extends ComboBulider{
    @Override
    public void builder() {
        this.addProduct(Product.PRODUCT1);
        this.addProduct(Product.PRODUCT3);
    }
    @Override
    public void disCount() {
        this.setDiscount(5);
    }
}
public class Combo2Bulider extends ComboBulider{
    @Override
    public void builder() {
        this.addProduct(Product.PRODUCT1);
        this.addProduct(Product.PRODUCT2);
        this.addProduct(Product.PRODUCT3);
    }
    @Override
    public void disCount() {
        this.setDiscount(10);
    }
代码4:接口类,与客户端打交道的,这里为Server
package com.xdnote.DesignPattern.creational.bulider;
/**
 * Server在Buider充当角色: 服务员
 * 和工厂一样:接收命令,再返回最终需要的实体对象
 * 和工厂不一样:工厂收到命令就直接做菜了,而构造收到命令后 要再给工厂去做,
 * 工厂就好比杂货商,买一个馒头我就给你一个馒头,买一个包子我就给你一个包子,客户直接和你的生产地打交道
 * 而构造则是买一个馒头,则告诉做馒头的伙计去做一个馒头,做完了,再取走,再给客户,客户只和你的服务员打交道
 * */
/**
 * 作为服务员:应该有
 * 接收客户的命令(被点餐)
 * 去厂房拿货(去通知作餐)
 * 把货给客户(取餐,取餐给用户之前要打折)
 * */
/**
 * 适用性,
 * */
public class Server {
    //呼叫服务员
    private ComboBulider bulider ;
    public Server(){}
    //服务员要知道客户需要什么,然后实例化需要的套餐制作人员
    public void setBuider(ComboBulider bulider){
        this.bulider = bulider;
    }
    public Combo getCombo(){
        //通知套餐制作人员制作套餐
        this.bulider.bulidCombo();
        //服务员要完成打打折,当然他不知道具体的折扣
        this.bulider.disCount();
        //打完折后取餐
        return this.bulider.getCombo();
    }
}
代码5:客户端调用
    public static void main(String[] args) {
        Server server = new Server();
        server.setBuider(new Combo1Bulider());
        Combo combo = server.getCombo();
        System.out.println(combo);
        Server server2 = new Server();
        server2.setBuider(new Combo2Bulider());
        Combo combo2 = server2.getCombo();
        System.out.println(combo2);
    }
小结
构造者模式 Builder
- 使用频率:
低 
可能是由于Web项目结构简单,一般情况下很少用构造者模式去创建对象。
- 利弊影响:
低 
利:对类型固定的对象很容易组合,理解此模式可以很好的理解面向对象思想。
弊:构造器模式其实只是实现了单产品与多产品对象的松耦合,灵活性上好像还不怎么样。
- 小评:
 
个人在Java中好像非常少的使用,相反在Javascript里面还使用过一些,虽然是函数式的语言,但也可以用面向对象的思维去写嘛。比如prototype什么的。