建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。主要用于解决在软件系统中,有时候面临着”一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。简而言之,就是当我们需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们需要应用建造者模式。
建造者模式可以将一个产品的内部表象与产品生成过程分割开来,从而可以是一个建造过程生成具有不同的内部表象的产品对象。如果我们使用了建造者模式,那么用户就只需指定建造者的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。
大话设计模式中程杰老师给出的定义是,建造者模式:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
建造者模式结构图如下:
基本代码如下:
//Product产品类,由多个对象组成
public class Prodct{
List productParts = new ArrayList();
//添加产品部件
public void addProductParts(String productPart){
productParts.add(productPart);
}
//列举所有的产品部件
public void show(){
for(productPart : productParts){
System.out.println(productPart);
}
}
}
//Builder抽象建造者类,确定产品有两个部件PartA和PartB组成
public class abstract Builder{
public abstract void builderPartA();
public abstract void builderPartB();
//声明一个得到产品建造后结果的方法getResult()
public abstract Product getResult();
}
//具体建造者类1
public class ConcreteBuilder1 extends Builder{
private Product product = new Product();
@override
public void buildPartA(){
product.addProductParts("part A");
}
@override
public void buildPartB(){
product.addProductParts("part B");
}
@override
public Product getResult(){
return product;
}
}
//具体建造者类2
public class ConcreteBuilder2 extends Builder{
private Product product = new Product();
@override
public void buildPartA(){
product.addProductParts("part X");
}
@override
public void buildPartB(){
product.addProductParts("part Y");
}
@override
public Product getResult(){
return product;
}
}
//指挥者类
public class Director{
//用来指挥建造过程(根据传入具体Builder实现类的不同来建造具有不同部件的对象)
public void constructor(Builder builder){
builder.buildPartA();
builder.buildPartB();
}
}
//测试方法
public static void main(String[] args){
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
director.constructor(b1);
Product p1 = b1.getResult();
p1.show();
Builder b2 = new ConcreteBuilder2();
director.constructor(b2);
Product p2 = b2.getResult();
p2.show();
}
建造者模式是在当下创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时使用的模式。
再举一个生活中常见的例子:
假设一个快餐店的商业案例,其中,一个典型的套餐可以是由以下部分组成:一个汉堡(Burger)和一杯冷饮(Cold drink)。因为汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中,所以这个套餐的内部组成有不同的方式,结合建造者模式的定义“将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示”,该种案例完全可以使用建造者模式来实现。
我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。
然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的MealBuilder。BuilderPatternDemo,我们的演示类使用 MealBuilder 来创建一个 Meal。
//创建表示食物条目的接口
public interface Item{
public String name();
public Packing packing();
public float price();
}
//创建表示食物包装的接口
public interface Packing{
public String pack();
}
//创建实现Packing接口的实体类—包装纸包装
public class Wrapper implements Packing{
@override
public String pack(){
return "Wrapper";
}
}
//创建实现Packing接口的实体类—瓶子包装
public class Bottle implements Packing{
@override
public String pack(){
return "Bootle";
}
}
//创建了实现Item接口的抽象类汉堡类,该类提供了默认的功能
public abstract class Burger implements itm{
//汉堡采用包装纸包装
@override
public Packing packing(){
return new Wrapper();
}
@override
public abstract float price();
}
//创建了实现Item接口的抽象类冷饮类,该类提供了默认的功能
public abstract class ColdDrink implements itm{
//冷饮采用瓶子包装
@override
public Packing packing(){
return new Bottle();
}
@override
public abstract float price();
}
//创建扩展了Burger的实体类素食汉堡
public class VegBurger extends Burger{
@override
public float price(){
return 25.0f;
}
@override
public float name(){
return "Veg Burger";
}
}
//创建扩展了Burger的实体类鸡肉汉堡
public class ChickenBurger extends Burger{
@override
public float price(){
return 50.5f;
}
@override
public float name(){
return "Chicken Burger";
}
}
//创建扩展了ColdDrink的实体类可口可乐
public class Coke extends ColdDrink{
@override
public float price(){
return 30.0f;
}
@override
public float name(){
return "Coke";
}
}
//创建扩展了ColdDrink的实体类百事可乐
public class Pepsi extends ColdDrink{
@override
public float price(){
return 35.0f;
}
@override
public float name(){
return "Pepsi";
}
}
//创建一个套餐Meal类
import java.util.ArrayList;
import java.util.List;
public class Meal {
private List- items = new ArrayList
- ();
public void addItem(Item item){
items.add(item);
}
public float getCost(){
float cost = 0.0f;
for (Item item : items) {
cost += item.price();
}
return cost;
}
public void showItems(){
for (Item item : items) {
System.out.print("Item : "+item.name());
System.out.print(", Packing : "+item.packing().pack());
System.out.println(", Price : "+item.price());
}
}
}
//创建一个MealBuilder类,实际的builder类负责创建套餐Meal对象。
public class MealBuilder {
//素食套餐
public Meal prepareVegMeal (){
Meal meal = new Meal();
meal.addItem(new VegBurger());//素食汉堡
meal.addItem(new Coke());//可口可乐
return meal;
}
//肉食套餐
public Meal prepareNonVegMeal (){
Meal meal = new Meal();
meal.addItem(new ChickenBurger());//鸡肉汉堡
meal.addItem(new Pepsi());//百事可乐
return meal;
}
}
//测试方法
public classBuilderPatternTestDemo{
public static void main(String[] args){
MealBuilder mealBuilder = new MealBuilder();
Meal vegMeal = mealBuilder.prepareVegMeal();
System.out.println("Veg Meal");
vegMeal.showItems();
System.out.println("Total Cost: " +vegMeal.getCost());
Meal chickenVegMeal = mealBuilder.prepareNonVegMeal();
System.out.println("Chicken Veg Meal");
chickenVegMeal.showItems();
System.out.println("Total Cost: " +chickenVegMeal.getCost());
}
}
运行结果:
Veg Meal
Item : Veg Burger, Packing : Wrapper, Price : 25.0
Item : Coke, Packing : Bottle, Price : 30.0
Total Cost: 55.0
Chicken Veg Meal
Item : Chicken Burger, Packing : Wrapper, Price : 50.5
Item : Pepsi, Packing : Bottle, Price : 35.0
Total Cost: 85.5
使用实例:JAVA 中的 StringBuilder。
优点:
1、建造者独立,易扩展。
2、便于控制细节风险。
缺点:
1、产品必须有共同点,范围有限制。
2、如内部变化复杂,会有很多的建造类。
使用场景:
1、需要生成的对象具有复杂的内部结构。
2、需要生成的对象内部属性本身相互依赖。
注意事项:与工厂模式的区别建造者模式更加关注与零件装配的顺序。