建造者模式是一种创建型设计模式,它允许你分步骤创建复杂对象。该模式将对象的构造过程与其表示分离,使得同样的构造过程可以创建不同的表示。
-
工厂模式:
- 关注的是对象的创建,隐藏对象创建的细节
- 主要用于创建单一类型的对象
- 通常一步到位创建完整对象
-
建造者模式:
- 关注的是对象的组装过程,分步骤构建复杂对象
- 用于创建复杂对象,特别是需要多个步骤或配置的对象
- 强调对象的构造过程可以有不同的表示
举例说明: 现在的场景是,我们去快餐店里买食品时,经常会选择一些套餐。但是,为了促销,商家往往会将不同的食品(这里见简单起见,假设只有汉堡和可乐)进行组合售卖,从而就出现了各式各样的套餐。可实际上每项食品的制作过程和打包方式是不变的,然而却呈现出了不同的套餐,不同的价格。这就可视为对象的构建过程不变,但是表示(不同的套餐)是经常变化的场景。
源码地址: github.com/YaYiXiBa/Ja…
首先来确定一下类与接口: 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 <<<<<<<<<<<<<<<<<<<<<<<<<<<