设计模式(4):构造者模式 Builder

如果一个对象由多个元素组成,而且这些元素可组成不同的对象,用构造者模式去分离出这个对象的构造过程。

构造者模式 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什么的。