引言
生成器是一种创建型设计模式, 使你能够分步骤创建复杂对象。
与其他创建型模式不同, 生成器不要求产品拥有通用接口。 这使得用相同的创建过程生成不同的产品成为可能。
复杂度: 中等
流行度: 流行
使用示例: 生成器模式是 Java 世界中的一个著名模式。 当你需要创建一个可能有许多配置选项的对象时, 该模式会特别有用。
生成器在 Java 核心程序库中得到了广泛的应用:
- java.lang.StringBuilder#append() (
非同步
) - java.lang.StringBuffer#append() (
同步
) - java.nio.ByteBuffer#put() (还有 CharBuffer、 ShortBuffer、 IntBuffer、 LongBuffer、 FloatBuffer 和 DoubleBuffer)
- javax.swing.GroupLayout.Group#addComponent()
- java.lang.Appendable的所有实现
识别方法: 生成器模式可以通过类来识别, 它拥有一个构建方法和多个配置结果对象的方法。 生成器方法通常支持方法链 (例如 someBuilder.setValueA(1).setValueB(2).create()
)。
分步制造汽车
在本例中, 生成器模式允许你分步骤地制造不同型号的汽车。
示例还展示了生成器如何使用相同的生产过程制造不同类型的产品 (汽车手册)。
主管控制着构造顺序。 它知道制造各种汽车型号需要调用的生产步骤。 它仅与汽车的通用接口进行交互。 这样就能将不同类型的生成器传递给主管了。
最终结果将从生成器对象中获得, 因为主管不知道最终产品的类型。 只有生成器对象知道自己生成的产品是什么。
builders
builders/Builder.java: 通用生成器接口
package refactoring_guru.builder.example.builders;import refactoring_guru.builder.example.cars.CarType;
import refactoring_guru.builder.example.components.Engine;
import refactoring_guru.builder.example.components.GPSNavigator;
import refactoring_guru.builder.example.components.Transmission;
import refactoring_guru.builder.example.components.TripComputer;/*** Builder interface defines all possible ways to configure a product.*/
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);
}
builders/CarBuilder.java: 汽车生成器
/*** Concrete builders implement steps defined in the common interface.*/
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;}@Overridepublic void setSeats(int seats) {this.seats = seats;}@Overridepublic void setEngine(Engine engine) {this.engine = engine;}@Overridepublic void setTransmission(Transmission transmission) {this.transmission = transmission;}@Overridepublic void setTripComputer(TripComputer tripComputer) {this.tripComputer = tripComputer;}@Overridepublic void setGPSNavigator(GPSNavigator gpsNavigator) {this.gpsNavigator = gpsNavigator;}public Car getResult() {return new Car(type, seats, engine, transmission, tripComputer, gpsNavigator);}
}
builders/CarManualBuilder.java: 汽车手册生成器
/*** Unlike other creational patterns, Builder can construct unrelated products,* which don't have the common interface.** In this case we build a user manual for a car, using the same steps as we* built a car. This allows to produce manuals for specific car models,* configured with different features.*/
public class CarManualBuilder implements Builder{private CarType type;private int seats;private Engine engine;private Transmission transmission;private TripComputer tripComputer;private GPSNavigator gpsNavigator;@Overridepublic void setCarType(CarType type) {this.type = type;}@Overridepublic void setSeats(int seats) {this.seats = seats;}@Overridepublic void setEngine(Engine engine) {this.engine = engine;}@Overridepublic void setTransmission(Transmission transmission) {this.transmission = transmission;}@Overridepublic void setTripComputer(TripComputer tripComputer) {this.tripComputer = tripComputer;}@Overridepublic void setGPSNavigator(GPSNavigator gpsNavigator) {this.gpsNavigator = gpsNavigator;}public Manual getResult() {return new Manual(type, seats, engine, transmission, tripComputer, gpsNavigator);}
}
cars
cars/Car.java: 汽车产品
/*** Car is a product class.*/
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;}
}
cars/Manual.java: 手册产品
/*** Car manual is another product. Note that it does not have the same ancestor* as a Car. They are not related.*/
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;}
}
cars/CarType.java
package refactoring_guru.builder.example.cars;public enum CarType {CITY_CAR, SPORTS_CAR, SUV
}
components
components/Engine.java: 产品特征 1
/*** Just another feature of a car.*/
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;}
}
components/GPSNavigator.java: 产品特征 2
/*** Just another feature of a car.*/
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;}
}
components/Transmission.java: 产品特征 3
/*** Just another feature of a car.*/
public enum Transmission {SINGLE_SPEED, MANUAL, AUTOMATIC, SEMI_AUTOMATIC
}
components/TripComputer.java: 产品特征 4
/*** Just another feature of a car.*/
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");}}
}
director
director/Director.java: 主管控制生成器
/*** Director defines the order of building steps. It works with a builder object* through common Builder interface. Therefore it may not know what product is* being built.*/
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());}
}
Demo.java: 客户端代码
/*** Demo class. Everything comes together here.*/
public class Demo {public static void main(String[] args) {Director director = new Director();// Director gets the concrete builder object from the client// (application code). That's because application knows better which// builder to use to get a specific product.CarBuilder builder = new CarBuilder();director.constructSportsCar(builder);// The final product is often retrieved from a builder object, since// Director is not aware and not dependent on concrete builders and// products.Car car = builder.getResult();System.out.println("Car built:\n" + car.getCarType());CarManualBuilder manualBuilder = new CarManualBuilder();// Director may know several building recipes.director.constructSportsCar(manualBuilder);Manual carManual = manualBuilder.getResult();System.out.println("\nCar manual built:\n" + carManual.print());}}
OutputDemo.txt: 执行结果
Car built:
SPORTS_CARCar manual built:
Type of car: SPORTS_CAR
Count of seats: 2
Engine: volume - 3.0; mileage - 0.0
Transmission: SEMI_AUTOMATIC
Trip Computer: Functional
GPS Navigator: Functional