是设计模式,我们有救了!!!(三、建造者模式)

41 阅读4分钟

建造者模式是一种创建型设计模式,它允许你分步骤创建复杂对象。该模式将对象的构造过程与其表示分离,使得同样的构造过程可以创建不同的表示。

  • ​工厂模式​​:

    • 关注的是​​对象的创建​​,隐藏对象创建的细节
    • 主要用于创建​​单一类型​​的对象
    • 通常一步到位创建完整对象
  • ​建造者模式​​:

    • 关注的是​​对象的组装过程​​,分步骤构建复杂对象
    • 用于创建​​复杂对象​​,特别是需要多个步骤或配置的对象
    • 强调对象的构造过程可以有不同的表示

举例说明: 现在的场景是,我们去快餐店里买食品时,经常会选择一些套餐。但是,为了促销,商家往往会将不同的食品(这里见简单起见,假设只有汉堡和可乐)进行组合售卖,从而就出现了各式各样的套餐。可实际上每项食品的制作过程和打包方式是不变的,然而却呈现出了不同的套餐,不同的价格。这就可视为对象的构建过程不变,但是表示(不同的套餐)是经常变化的场景。

源码地址: github.com/YaYiXiBa/Ja…

image.png

首先来确定一下类与接口: Item:选项。不管是什么商品,都必须实现此接口。因为作为商品,最起码要有名字,价格,和打包方式。其实也不一定非要是接口,作为抽象类不行吗?可以,但是,举例来说“鸡肉汉堡”要继承自“汉堡”抽象类,java是单一继承的,“汉堡”抽象类又要再一次继承Item。过多的继承并不明智。记得抽象类和接口的区别吗?接口可以多实现。并且侧重于功能,而抽象类侧重于分类。

public interface Item {
    public String name();
    public Packing packing();
    public float price();
}

Burger:抽象类,所有汉堡的父类。汉堡一定是用Wrapper盒子装的,因此packing()可以直接在父类中实现。

public abstract class Burger implements Item {

    @Override
    public Packing packing() {
        return new Wrapper();
    }

    @Override
    public abstract float price();
}

汉堡的具体的实现:鸡肉汉堡

public class ChickenBurger extends Burger{
    @Override
    public String name() {
        return "鸡肉汉堡";
    }

    @Override
    public float price() {
        return 20f;
    }
}

或者:蔬菜汉堡

public class VegBurger extends Burger {
    @Override
    public String name() {
        return "蔬菜汉堡";
    }

    @Override
    public float price() {
        return 10f;
    }
}

ColdDrink:冷饮,与汉堡相似。可乐一定是用瓶子(Bottle)装的,packing()可以直接在抽象类中声明。

public abstract class ColdDrink implements Item {


    @Override
    public Packing packing() {
        return new Bottle();
    }

    @Override
    public abstract float price();
}

具体实现:可口可乐

public class Coke extends ColdDrink{
    @Override
    public String name() {
        return "可口可乐";
    }

    @Override
    public float price() {
        return 5f;
    }
}

或者:百事可乐

public class Pepsi extends ColdDrink{
    @Override
    public String name() {
        return "百事可乐";
    }

    @Override
    public float price() {
        return 5f;
    }
}

Bottle和Wrapper都是用来打包的因此二者都实现了Packing接口:

public interface Packing {
    public String packing();
}
public class Wrapper implements Packing{

    @Override
    public String packing() {
        return "纸盒";
    }
}
public class Bottle implements Packing{

    @Override
    public String packing() {
        return "瓶子";
    }
}

以上关系梳理清楚之后,便要开始组建“套餐”Meal了。

public class Meal {
    //套餐中包含的所有项目
    private  final ArrayList<Item> items = new ArrayList<>();
    public void addItem(Item item){
        items.add(item);
    }
    //套餐价格的计算
    public float getCost(){
        return (float) items.stream().mapToDouble(Item::price).sum();
    }
    //展示套餐
    public void show(){
        items.forEach(e->{
            System.out.println("-----------------");
            System.out.println(e.name());
            System.out.println(e.packing().packing());
            System.out.println(e.price());
        });
    }
}

Meal本身并没有提供构建方式,只提供了添加Item的方法。接下来的创建过程,交给MealBuilder来实现。在MealBuilder中可以自由的添加各种组合套餐,MealBuilder的作用就是用来创建各种不同的Meal。如此,外部只需要有了MealBuilder就不再需要关注,不同汉堡和可乐的构建以及打包过程,也不需要自己创建一个Meal再各种填充Item。直接调用MealBuilder的方法就可以得到一个套餐。

public class MealBuilder {
    //蔬菜汉堡和可口可乐套餐
    public Meal VegAndCoke (){
        Meal meal = new Meal();
        meal.addItem(new VegBurger());
        meal.addItem(new Coke());
        return meal;
    }
    //鸡肉汉堡和百事可乐套餐
    public Meal CheckAndPepsi (){
        Meal meal = new Meal();
        meal.addItem(new ChickenBurger());
        meal.addItem(new Pepsi());
        return meal;
    }
}

客户端使用:

public class Client {
    public static void main(String[] args) {
        MealBuilder mealBuilder = new MealBuilder();

        Meal vegAndCoke = mealBuilder.VegAndCoke();
        vegAndCoke.show();
        vegAndCoke.getCost();
        System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<");

        Meal checkAndPepsi = mealBuilder.CheckAndPepsi();
        checkAndPepsi.show();
        checkAndPepsi.getCost();
        System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<");
    }
}

运行结果:

蔬菜汉堡 纸盒 10.0

可口可乐 瓶子 5.0 <<<<<<<<<<<<<<<<<<<<<<<<<<<

鸡肉汉堡 纸盒 20.0

百事可乐 瓶子 5.0 <<<<<<<<<<<<<<<<<<<<<<<<<<<