引言
建造者模式(Builder Pattern)使用多个简单对象一步一步构建成一个复杂的对象。这种类型的设计模式属于建造型模式,它提供了一种创建对象的最佳方式。
一个Builder会一步步构建最终的对象。该Builder类是独立于其他对象的。
实现概要
建造者模式的实现并没有一个特别经典的套路,原因是在多数情况下复杂对象的构建往往千奇百怪。但为了更好的理解建造者模式使用的场景,我们假设如下的功能需要:
因为建造者模式就是为了构建复杂对象,为了更加贴近这一点,以午餐(Meal)作为最终要被构建的对象,我们假设:午餐中分为食物(Item)和包装(Packing)—>食物包含汉堡(Burger)和冷饮(ColdDrink)两种;汉堡有鸡肉汉堡(ChickenBurger)和蔬菜汉堡(VegBurger)之分;冷饮有可口可乐(Coke)和百事可乐(Pepsi)之分;包装又分为瓶装(Bottle)和袋装(Wrapper)两种。
如果你看不懂上面的描述,或者已经准备关闭浏览器去做眼睛保健操,那么下面的结构图可能对你有所帮助:
实现过程
一、创建基础接口
创建食物接口及具体实现类,创建包装接口及具体包装类:
public interface Item {
/** 食物名称*/
String name();
/** 包装*/
Packing packing();
/** 总价*/
float price();
}
public abstract class Burger implements Item {
@Override
public Packing packing() {
return new Wrapper();
}
}
public class ChickenBurger extends Burger {
@Override
public String name() {
return "Chicken Burger";
}
@Override
public float price() {
return 50.5f;
}
}
public class VegBurger extends Burger {
@Override
public String name() {
return "Veg Burger";
}
@Override
public float price() {
return 25.0f;
}
}
public abstract class ColdDrink implements Item {
@Override
public Packing packing() {
return new Bottle();
}
}
public class Coke extends ColdDrink {
@Override
public String name() {
return "Coke";
}
@Override
public float price() {
return 30.0f;
}
}
public class Pepsi extends ColdDrink {
@Override
public String name() {
return "Pepsi";
}
@Override
public float price() {
return 35.0f;
}
}
public interface Packing {
String pack();
}
public class Bottle implements Packing {
@Override
public String pack() {
return "Bottle";
}
}
public class Wrapper implements Packing {
@Override
public String pack() {
return "Wrapper";
}
}
二、创建目标类型
此例中,目标类型即午餐类(Meal)
public class Meal {
private List<Item> items = new ArrayList<Item>();
public Meal addAll(List<? extends Item> items) {
this.items.addAll(items);
return this;
}
public Double getSum() {
return this.items.stream()
.collect(Collectors.summarizingDouble(Item::price))
.getSum();
}
public Double getAverage() {
return this.items.stream()
.collect(Collectors.summarizingDouble(Item::price))
.getAverage();
}
public void showItems() {
this.items.forEach(item -> {
System.out.print("Item : " + item.name());
System.out.print(", Packing : " + item.packing()
.pack());
System.out.println(", Price : " + item.price());
});
}
}
三、创建建造者类
public class MealBuilder {
public Meal prepareMeal(Item... items) {
return new Meal().addAll(Arrays.asList(items));
}
}
四、测试
public class BuilderPatternDemo {
public static void main(String[] args) {
MealBuilder mealBuilder = new MealBuilder();
Meal vegMeal = mealBuilder.prepareMeal(new VegBurger(), new Coke());
System.out.println("Veg Meal");
vegMeal.showItems();
System.out.println("Total Cost: " + vegMeal.getSum());
Meal nonVegMeal = mealBuilder.prepareMeal(new ChickenBurger(), new Pepsi());
System.out.println("\n\nNon-Veg Meal");
nonVegMeal.showItems();
System.out.println("Total Cost: " + nonVegMeal.getSum());
}
}
执行结果:
总结
意图:建造者模式的用意就是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示,例如本例中相同的创建午餐的方式,但使用不同的基础对象,最终得出不一样的套餐。
使用场景:一些基础部件不会变,而其组合经常变化的时候。主要解决软件系统中,有时候会面临“一个复杂对象”的创建工作,其通常由多个子对象用一定的算法构成。由于需求的变化,这个复杂对象的各个部件经常面临着剧烈的变化,但将它们组合在一起的算法相对稳定。
优点:建造者独立,易扩展;便于控制细节风险。
缺点:产品必须有共同点,范围有限制;内部变化复杂,会有很多建造类。
鸣谢
《建造者模式》