Builder模式:御凤仙姑在北美开了家中式快餐店

家乡的口味,西式的标准

自从和四大炼丹术士在爪娲山一别之后,御凤独自一人来到了亚美利加。由于吃腻了左宗棠鸡,李鸿章杂碎,她觉得自己应该做点什么,自己的那十几口炼丹炉平时闲着也没别的用,不如做饭吧。说干就干,你有肯德基,我有玛萨基。御凤用炼丹挣来的闲钱,在家门口开了一家中式快餐店,名字就叫玛萨基。

玛萨基用餐流程简明,效率高超。玛萨基的厨房有主食、汤、自选菜、水果、饮料五大区域,根据用户的选择,通过自动传送带,构建出成品套餐以供用户享用。主食有米饭、白粥、烂糊面可选,汤有冬瓜排骨汤、罗宋汤、滋补牛鞭汤等选择,其余不再赘述。玛萨基提供两种套餐:标准套餐和商务套餐,其中标准套餐由主食、汤、自选菜组成,不含水果饮料,商务套餐五种都包含。

标准套餐 商务套餐
主食
自选菜
水果 ×
饮品 ×

御凤见招拆招,用了Builder模式来对付她的玛萨基套餐这个复杂的Product,第一版代码如下

Client.class

public class Client {
    public static void main(String[] args) {
        玛萨基套餐Builder builder = new 标准套餐Builder();
        Director director1 = new Director(builder);
        菜[] dishes1 = {new 海蜇皮(), new 白斩鸡()};
        菜[] dishes2 = {new 红烧羊肉(), new 白斩鸡()};
        director1.construct标准套餐(new 烂糊面(), dishes1, new 罗宋汤());
        System.out.println(builder.create().toString());


        玛萨基套餐Builder 商务套餐Builder = new 商务套餐Builder();
        Director director2 = new Director(商务套餐Builder);
        director2.construct商务套餐(new 米饭(), dishes2, new 牛鞭汤(), new 绍兴黄酒(), new 香蕉());
        商务套餐Builder businessBuilder = (商务套餐Builder) 商务套餐Builder;
        System.out.println(businessBuilder.create().toString());
    }
}

Director.class

public class Director {
    玛萨基套餐Builder builder = null;

    public Director(玛萨基套餐Builder builder) {
        this.builder = builder;
    }

    public void construct标准套餐(主食 stapleFood, 菜[] dishes, 汤 soup) {
        builder.build主食(stapleFood);
        builder.build自选菜(dishes);
        builder.build汤(soup);
    }

    public void construct商务套餐(主食 stapleFood, 菜[] dishes, 汤 soup, 饮料 beverage, 水果 fruit) {
        builder.build主食(stapleFood);
        builder.build自选菜(dishes);
        builder.build汤(soup);
        商务套餐Builder businessBuilder = (商务套餐Builder) builder;
        businessBuilder.build饮料(beverage);
        businessBuilder.build水果(fruit);
    }

}

玛萨基套餐.class

public abstract class 玛萨基套餐 {
    protected 主食 stapleFood;
    protected 菜[] dishes;
    protected 汤 soup;


    public 玛萨基套餐() {
    }

    public void setStapleFood(主食 stapleFood) {
        this.stapleFood = stapleFood;
    }

    public void setDishes(菜[] dishes) {
        this.dishes = dishes;
    }


    public void setSoup(汤 soup) {
        this.soup = soup;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder()
                .append("主食是:").append(stapleFood.getClass().getSimpleName())
                .append(", 菜有丰盛的");
        for (菜 dish : dishes) {
            sb.append(dish.getClass().getSimpleName() + ",");
        }
        sb.append(" 汤是上好的").append(soup.getClass().getSimpleName()).toString();
        return sb.toString();
    }
}

商务套餐.class

public class 商务套餐 extends 玛萨基套餐 {
    protected 水果 fruit;
    protected 饮料 beverage;

    public void setFruit(水果 fruit) {
        this.fruit = fruit;
    }

    public void setBeverage(饮料 beverage) {
        this.beverage = beverage;
    }

    @Override
    public String toString() {
        return super.toString() +
                ", 水果是" + fruit.getClass().getSimpleName() +
                ", 饮料是" + beverage.getClass().getSimpleName();
    }
}

玛萨基套餐Builder.class

public abstract class 玛萨基套餐Builder {
    public abstract void build汤(汤 soup);

    public abstract void build主食(主食 stapleFood);

    public abstract void build自选菜(菜[] dishes);

    public abstract 玛萨基套餐 create();

}

标准套餐Builder.class

public class 标准套餐Builder extends 玛萨基套餐Builder {
    private 玛萨基套餐 massage = new 标准套餐();


    @Override
    public void build汤(汤 soup) {
        massage.setSoup(soup);
    }

    @Override
    public void build主食(主食 stapleFood) {
        massage.setStapleFood(stapleFood);
    }

    @Override
    public void build自选菜(菜[] dishes) {
        massage.setDishes(dishes);
    }

    @Override
    public 玛萨基套餐 create() {
        return massage;
    }
}

商务套餐Builder.class

public class 商务套餐Builder extends 玛萨基套餐Builder {
    private 商务套餐 massage = new 商务套餐();

    @Override
    public void build汤(汤 soup) {
        massage.setSoup(soup);
    }

    @Override
    public void build主食(主食 stapleFood) {
        massage.setStapleFood(stapleFood);
    }

    @Override
    public void build自选菜(菜[] dishes) {
        massage.setDishes(dishes);
    }

    public void build饮料(饮料 beverage) {
        massage.setBeverage(beverage);
    }

    public void build水果(水果 fruit) {
        massage.setFruit(fruit);
    }

    @Override
    public 玛萨基套餐 create() {
        return massage;
    }
}

运行结果

Builder模式和Abstract Factory的区别

Builder Abstract Factory
一步步构建一个复杂的product对象 着重于一组product对象的创建
最后一步返回product 立即返回product

简单Builder模式在Java中的运用

结构图

Builder模式:御凤仙姑在北美开了家中式快餐店_第1张图片

  • Client类
  • 创建Builder和Director对象
  • 将Builder的引用传递给Director
    1. 通过Director的构造函数传入Director director = new Director(xBuilder);
    • 通过Director的方法传入director.setBuilder(xBuilder);
  • 通过Director的construct方法调用Builder的各个buildPart方法,完成Product的构建
  • Product类
  • 如果Product种类比较多
    • Product作为抽象类,具体的产品继承该父类
    • new Product()放在具体产品的Builder中private Product product = new ConcreteProductA();
    • 抽象Builder类提供一个getProduct()方法,在具体的Builder返回具体的Product引用
    • Director的唯一功能就是调用Builder,将各个Part构建起来
  • 如果只有一种Product
    • Product可以是一个具体类
    • new Product()放在抽象Builder中,并对外提供一个createProduct()方法
    • 在Director的construct方法中调用Builder的createProduct()方法
    • 在Director中提供一个getProduct()方法,返回具体Product引用
总结
  • Builder Pattern作为创建型模式,其着眼点在于Product,一切都是围绕这个Product的创建而展开的
  • Product由于整体较为复杂,将其拆分成若干Part,Builder负责将每个部分build好
    • 静态层面Variable,Product类有许多成员变量需要设置值,用Builder模式来替代使用多参数的构造函数
    • 动态层面Method,Product可以拆分成若干步骤,每一步又有其不同的具体实现方法(参见GOF-P75)
  • 抽象Builder提供一个方法,用来给Client类通过Builder来得到最后生成的Product对象
  • Builder模式可以精简实现,参见Android的AlertDialog

参考资料

Sourcemaking
Design Patterns in Java Tutorial
Wiki:Builder pattern

你可能感兴趣的:(Builder模式:御凤仙姑在北美开了家中式快餐店)