Builder Pattern.
别名:生成器模式
定义
将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
应用场景
1.避免 “ 重叠构造函数 ( telescopic constructor ) ”的出现
2.使用代码创建不同形式的产品
当你需要创建各种形式的产品,它们制造过程相似且仅有细节上的差异【基本生成器接口中定义了所有可能的制造步骤,具体生成器将实现这些步骤来制造特定形式的产品。同时,主管类将负责管理制造步骤的顺序】
3.使用生成器构造组合树或其他复杂对象
生成器模式让你能分步骤构造产品。则可以通过延迟执行某些步骤而不影响最终产品。你甚至可以通过递归这些步骤。【生成器不能对外发布未完成的产品。这样可以避免客户端代码获取不完整结果对象的情况】
实现方法
1.清晰地定义通用步骤,确保它们可以制造所有形式的产品。
2.在基本生成器接口声明这些步骤
3.为每个形式的产品创建具体生成器类,并实现其构造步骤
不要忘记实现获取构造结果对象的方法。不能在生成器接口中声明方法,因不同生成器构造的产品可能没有公共接口,因此不知道该方法返回的对象类型。但是,如果所有产品都位于单一类层次中,便可以安全地基本接口中获取生成对象的方法
4.考虑创建主管类。它可以使用同一生成器对象来封装多种构造产品的方法
5.客户端代码会同时创建生成器和主管对象。构造开始前,客户端必须将生成器对象传递给主管对象
6.只有在所有产品都遵循相同接口的情况下,构造结果可以直接通过主管类获取。否则,客户端应当通过生成器获取构造结构
Builder和Director是如何和一个客户协作的
sequenceDiagram participant Client participant Director participant ConcreteBuilder Client->>ConcreteBuilder:new ConcreteBuilder Client->> Director:new Director(ConcreteBuilder) Client->> Director:Construct() Director->>ConcreteBuilder:BuilderPartA() Director->>ConcreteBuilder:BuilderPartB() Director->>ConcreteBuilder:BuilderPartC() Client->>ConcreteBuilder:GetResult()
结构
UML图
classDiagram
Builder<--o Director
ConcreteBuilder1..|>Builder
ConcreteBuilder2..|>Builder
ConcreteBuilder1-->Product1
ConcreteBuilder2-->Product2
Client..>ConcreteBuilder1
Client-->Director
class Director{
-builder:Builder
+Direcotr(builder)
+changeBuilder(builder)
+make(type)
}
class Builder{
<<interface>>
+reset()
+buildStepA()
+buildStepB()
+buildStepC()
}
class ConcreteBuilder1{
-result:Product1
+reset()
+buildStepA()
+buildStepB()
+buildStepC()
+getResult() Product1
}
class ConcreteBuilder2{
-result:Product2
+reset()
+buildStepA()
+buildStepB()
+buildStepC()
+getResult() Product2
}
参与者
1.生成器( Builder ) :接口声明在所有类型生成器中通用的产品构造步骤
2.具体生成器 ( Concrete Builder ) :提供构造过程的不同实现。具体生成器也可以构造不遵循通用接口的产品
3.产品( Products ) :是最终生成的对象。由不同生成器构造的产品无需属于同一类层次接口或接口
4.主管( Director ) :类定义调用构造步骤的顺序,这样你就可以创建和复用特定的产品配置
5.客户端( Client ) :必须与某个生成器对象与主管类关联
通用写法
public class Product1 {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product1{" +
"name='" + name + ''' +
'}';
}
}
public class Product2 {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product2{" +
"name='" + name + ''' +
'}';
}
}
public interface Builder {
void reset();
void buildStepA();
void buildStepB();
void buildStepC();
}
public class ConcreteBuilder1 implements Builder{
private Product1 result;
@Override
public void reset() {
result = new Product1();
}
@Override
public void buildStepA() {
result.setName("simple_1");
System.out.println("Product1 --> StepA");
}
@Override
public void buildStepB() {
System.out.println("Product1 --> StepB");
}
@Override
public void buildStepC() {
System.out.println("Product1 --> StepC");
}
public Product1 getResult() {
return result;
}
}
public class ConcreteBuilder2 implements Builder{
private Product2 result;
@Override
public void reset() {
result = new Product2();
}
@Override
public void buildStepA() {
result.setName("simple_2");
System.out.println("Product2 --> StepA");
}
@Override
public void buildStepB() {
System.out.println("Product1 --> StepB");
}
@Override
public void buildStepC() {
System.out.println("Product1 --> StepC");
}
public Product2 getResult() {
return result;
}
}
public class Director {
private Builder builder;
Director(Builder builder){
this.builder = builder;
}
public void changeBuilder(Builder builder){
this.builder = builder;
}
public void make(String type){
builder.reset();
if (type.equals("simple")){
builder.buildStepA();
}else {
builder.buildStepB();
builder.buildStepC();
}
}
}
public class Client {
public static void main(String[] args) {
ConcreteBuilder1 concreteBuilder1 = new ConcreteBuilder1();
Director director = new Director(concreteBuilder1);
director.make("simple");
System.out.println(concreteBuilder1.getResult());
}
}
案例
分步制造汽车
主管控制着构造顺序。 它知道制造各种汽车型号需要调用的生产步骤。 它仅与汽车的通用接口进行交互。 这样就能将不同类型的生成器传递给主管了。
最终结果将从生成器对象中获得, 因为主管不知道最终产品的类型。 只有生成器对象知道自己生成的产品是什么。
Components
public class Engine {
private final double volume;
private double mileage;
private boolean started;
public Engine(double volume, double mileage) {
this.volume = volume;
this.mileage = mileage;
}
public void on() {
started = true;
}
public void off() {
started = false;
}
public boolean isStarted() {
return started;
}
public void go(double mileage) {
if (started) {
this.mileage += mileage;
} else {
System.err.println("Cannot go(), you must start engine first!");
}
}
public double getVolume() {
return volume;
}
public double getMileage() {
return mileage;
}
}
public class GPSNavigator {
private String route;
public GPSNavigator() {
this.route = "221b, Baker Street, London to Scotland Yard, 8-10 Broadway, London";
}
public GPSNavigator(String manualRoute) {
this.route = manualRoute;
}
public String getRoute() {
return route;
}
}
public enum Transmission {
SINGLE_SPEED, MANUAL, AUTOMATIC, SEMI_AUTOMATIC
}
public class TripComputer {
private Car car;
public void setCar(Car car) {
this.car = car;
}
public void showFuelLevel() {
System.out.println("Fuel level: " + car.getFuel());
}
public void showStatus() {
if (this.car.getEngine().isStarted()) {
System.out.println("Car is started");
} else {
System.out.println("Car isn't started");
}
}
}
Builder
public interface Builder {
void setCarType(CarType type);
void setSeats(int seats);
void setEngine(Engine engine);
void setTransmission(Transmission transmission);
void setTripComputer(TripComputer tripComputer);
void setGPSNavigator(GPSNavigator gpsNavigator);
}
public class CarBuilder implements Builder{
private CarType type;
private int seats;
private Engine engine;
private Transmission transmission;
private TripComputer tripComputer;
private GPSNavigator gpsNavigator;
public void setCarType(CarType type) {
this.type = type;
}
@Override
public void setSeats(int seats) {
this.seats = seats;
}
@Override
public void setEngine(Engine engine) {
this.engine = engine;
}
@Override
public void setTransmission(Transmission transmission) {
this.transmission = transmission;
}
@Override
public void setTripComputer(TripComputer tripComputer) {
this.tripComputer = tripComputer;
}
@Override
public void setGPSNavigator(GPSNavigator gpsNavigator) {
this.gpsNavigator = gpsNavigator;
}
public Car getResult() {
return new Car(type, seats, engine, transmission, tripComputer, gpsNavigator);
}
}
public class CarManualBuilder implements Builder{
private CarType type;
private int seats;
private Engine engine;
private Transmission transmission;
private TripComputer tripComputer;
private GPSNavigator gpsNavigator;
@Override
public void setCarType(CarType type) {
this.type = type;
}
@Override
public void setSeats(int seats) {
this.seats = seats;
}
@Override
public void setEngine(Engine engine) {
this.engine = engine;
}
@Override
public void setTransmission(Transmission transmission) {
this.transmission = transmission;
}
@Override
public void setTripComputer(TripComputer tripComputer) {
this.tripComputer = tripComputer;
}
@Override
public void setGPSNavigator(GPSNavigator gpsNavigator) {
this.gpsNavigator = gpsNavigator;
}
public Manual getResult() {
return new Manual(type, seats, engine, transmission, tripComputer, gpsNavigator);
}
}
Cars
public enum CarType {
CITY_CAR, SPORTS_CAR, SUV
}
public class Car {
private final CarType carType;
private final int seats;
private final Engine engine;
private final Transmission transmission;
private final TripComputer tripComputer;
private final GPSNavigator gpsNavigator;
private double fuel = 0;
public Car(CarType carType, int seats, Engine engine, Transmission transmission,
TripComputer tripComputer, GPSNavigator gpsNavigator) {
this.carType = carType;
this.seats = seats;
this.engine = engine;
this.transmission = transmission;
this.tripComputer = tripComputer;
if (this.tripComputer != null) {
this.tripComputer.setCar(this);
}
this.gpsNavigator = gpsNavigator;
}
public CarType getCarType() {
return carType;
}
public double getFuel() {
return fuel;
}
public void setFuel(double fuel) {
this.fuel = fuel;
}
public int getSeats() {
return seats;
}
public Engine getEngine() {
return engine;
}
public Transmission getTransmission() {
return transmission;
}
public TripComputer getTripComputer() {
return tripComputer;
}
public GPSNavigator getGpsNavigator() {
return gpsNavigator;
}
}
public class Manual {
private final CarType carType;
private final int seats;
private final Engine engine;
private final Transmission transmission;
private final TripComputer tripComputer;
private final GPSNavigator gpsNavigator;
public Manual(CarType carType, int seats, Engine engine, Transmission transmission,
TripComputer tripComputer, GPSNavigator gpsNavigator) {
this.carType = carType;
this.seats = seats;
this.engine = engine;
this.transmission = transmission;
this.tripComputer = tripComputer;
this.gpsNavigator = gpsNavigator;
}
public String print() {
String info = "";
info += "Type of car: " + carType + "\n";
info += "Count of seats: " + seats + "\n";
info += "Engine: volume - " + engine.getVolume() + "; mileage - " + engine.getMileage() + "\n";
info += "Transmission: " + transmission + "\n";
if (this.tripComputer != null) {
info += "Trip Computer: Functional" + "\n";
} else {
info += "Trip Computer: N/A" + "\n";
}
if (this.gpsNavigator != null) {
info += "GPS Navigator: Functional" + "\n";
} else {
info += "GPS Navigator: N/A" + "\n";
}
return info;
}
}
Director
public class Director {
public void constructSportsCar(Builder builder) {
builder.setCarType(CarType.SPORTS_CAR);
builder.setSeats(2);
builder.setEngine(new Engine(3.0, 0));
builder.setTransmission(Transmission.SEMI_AUTOMATIC);
builder.setTripComputer(new TripComputer());
builder.setGPSNavigator(new GPSNavigator());
}
public void constructCityCar(Builder builder) {
builder.setCarType(CarType.CITY_CAR);
builder.setSeats(2);
builder.setEngine(new Engine(1.2, 0));
builder.setTransmission(Transmission.AUTOMATIC);
builder.setTripComputer(new TripComputer());
builder.setGPSNavigator(new GPSNavigator());
}
public void constructSUV(Builder builder) {
builder.setCarType(CarType.SUV);
builder.setSeats(4);
builder.setEngine(new Engine(2.5, 0));
builder.setTransmission(Transmission.MANUAL);
builder.setGPSNavigator(new GPSNavigator());
}
}
Client
public class Client {
public static void main(String[] args) {
Director director = new Director();
CarBuilder builder = new CarBuilder();
director.constructSportsCar(builder);
Car car = builder.getResult();
System.out.println("Car built:\n" + car.getCarType());
CarManualBuilder manualBuilder = new CarManualBuilder();
director.constructSportsCar(manualBuilder);
Manual carManual = manualBuilder.getResult();
System.out.println("\nCar manual built:\n" + carManual.print());
}
}