Builder模式,又称生成器或构建者模式,属于对象创建型模式,侧重于一步一步的构建复杂对象,只有在构建完成后才会返回生成的对象。Builder模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
一、使用场景
1、当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时,比如买一台电脑,我不需要知道电脑CPU,主板,机箱是如何生产的,也不需要知道它们是如何组装的。
2、当构造过程必须允许被构造的对象有不同的表示时,比如一台电脑即可以使用AMD的CPU,也可以使用Inter的CPU,这些都是可以根据需求变化的。
二、UML图
三、Java实现
示例1:
package study.patterns.builder; /** * 构建者模式:将一个复杂对象的构建与它的表示分离, * 使得同样的构建过程可以创建不同的表示。 * @author qbg * */ public class BuilderPattern { public static void main(String[] args) { ComputerBuilder builder = new HotDeskComputerBuilder(); Director director = new Director(builder); Computer computer = director.construct(); System.out.println("电脑组装完成:"); System.out.println(computer); } } /** * 机箱抽象类 */ abstract class Crate{ @Override public String toString() { return "abstract crate..."; } } /** * 酷冷至尊机箱 */ class CoolerMasterCrate extends Crate{ @Override public String toString() { return "CoolerMaster crate..."; } } /** * CPU抽象类 */ abstract class CPU{ @Override public String toString() { return "abstract cpu..."; } } /** * AMD CPU */ class AMDCPU extends CPU{ @Override public String toString() { return "AMD cpu..."; } } /** * 主板抽象类 */ abstract class Motherboard{ @Override public String toString() { return "abstract motherboard..."; } } /** * 华硕主板 */ class ASUSMotherboard extends Motherboard{ @Override public String toString() { return "ASUS motherboard..."; } } /** * 电脑定义类 */ class Computer{ CPU cpu; //cpu Motherboard motherboard; //主板 Crate crate;//机箱 @Override public String toString() { return "CPU:"+cpu+"\nMotherboard:"+motherboard+"\nCrate:"+crate; } } /** * 电脑构建者接口 */ interface ComputerBuilder{ public ComputerBuilder buildCPU(); public ComputerBuilder buildMotherboard(); public ComputerBuilder buildCrate(); public Computer getProduct(); } /** * 最热台式电脑构建实现类 */ class HotDeskComputerBuilder implements ComputerBuilder{ private Computer computer; public HotDeskComputerBuilder(){ this.computer = new Computer(); } @Override public ComputerBuilder buildCPU() { computer.cpu = new AMDCPU(); return this; } @Override public ComputerBuilder buildMotherboard() { computer.motherboard = new ASUSMotherboard(); return this; } @Override public ComputerBuilder buildCrate() { computer.crate = new CoolerMasterCrate(); return this; } @Override public Computer getProduct() { buildMotherboard().buildCPU().buildCrate(); return computer; } } /** * 导向器,客户端通过导向器获取产品, * 而不关心导向器是怎样获取到Builder生成器 * 构建的产品对象的。而具体的构建过程则交给具体的Builder。 */ class Director{ private ComputerBuilder builder; public Director(ComputerBuilder builder){ this.builder = builder; } /** * 返回构造好的产品 */ public Computer construct(){ return builder.getProduct(); } }
运行结果:
电脑组装完成: CPU:AMD cpu... Motherboard:ASUS motherboard... Crate:CoolerMaster crate...
在复杂对象有多个可变参数,且后续有可能继续增加的情况下,最好使用Builder模式来构建对象,如下:
示例2:
package study.patterns.builder; /** * Builder模式,用于大量可选参数对象的构建(大于4个或内部属性经常扩展) * @author qbg * 不可变类 */ public class NutritionFacts { private final int servings;//每份含量 必需 private final int calories;//卡路里 可选 private final int fat;//脂肪 可选 private final int sodium;//钠 可选 private final int carbohydrate;//碳水化合物 可选 public static class Builder{ //必需参数 private final int servings; //可选参数 private int calories = 0; private int fat = 0; private int sodium = 0; private int carbohydrate = 0; public Builder(int servings){ this.servings = servings; } public Builder calories(int cal){ calories = cal; return this; } public Builder fat(int fat){ this.fat = fat; return this; } public Builder sodium(int sod){ this.sodium = sod; return this; } public Builder carbohydrate(int car){ this.carbohydrate = car; return this; } public NutritionFacts build(){ return new NutritionFacts(this); } } /* *私有化构造器,创建该对象只能通过构建器 */ private NutritionFacts(Builder builder){ servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } public void print(){ System.out.println("servings:"+servings); System.out.println("calories:"+calories); System.out.println("fat:"+fat); System.out.println("sodium:"+sodium); System.out.println("carbohydrate:"+carbohydrate); } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts.Builder(600).calories(20) .carbohydrate(300).build(); System.out.println("可口可乐营养成分:"); cocaCola.print(); } }
运行结果:
可口可乐营养成分: servings:600 calories:20 fat:0 sodium:0 carbohydrate:300
四、模式优缺点
优点:
1、可以改变一个产品的内部表示,比如示例中只要实现一个新的ComputerBuilder就能改变电脑的内部组件,因为电脑的表示和内部结构是独立于客户端代码的。
2、将构造代码和表示代码分离,构造代码相当于builder,表示代码相当于director。不同的导向器可以使用相同的生成器来构造不同的产品。
3、Builder模式允许我们对构造过程进行更精细的控制,比如示例2中可以在构建过程加入有效性验证等。