使用示例:生成器模式是 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()
)。
01分步制造骑车
在本例中, 生成器模式允许你分步骤地制造不同型号的汽车。
示例还展示了生成器如何使用相同的生产过程制造不同类型的产品 (汽车手册)。
主管控制着构造顺序。 它知道制造各种汽车型号需要调用的生产步骤。 它仅与汽车的通用接口进行交互。 这样就能将不同类型的生成器传递给主管了。
最终结果将从生成器对象中获得, 因为主管不知道最终产品的类型。 只有生成器对象知道自己生成的产品是什么。
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: 汽车生成器
package refactoring_guru.builder.example.builders; import refactoring_guru.builder.example.cars.Car; 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; /** * 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; } @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); } }
builders/CarManualBuilder.java: 汽车手册生成器
package refactoring_guru.builder.example.builders; import refactoring_guru.builder.example.cars.Manual; 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; /** * 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; @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
cars/Car.java: 汽车产品
package refactoring_guru.builder.example.cars; 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; /** * 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: 手册产品
package refactoring_guru.builder.example.cars; 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; /** * 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
package refactoring_guru.builder.example.components; /** * 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
package refactoring_guru.builder.example.components; /** * 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
package refactoring_guru.builder.example.components; /** * Just another feature of a car. */ public enum Transmission { SINGLE_SPEED, MANUAL, AUTOMATIC, SEMI_AUTOMATIC }
components/TripComputer.java: 产品特征 4
package refactoring_guru.builder.example.components; import refactoring_guru.builder.example.cars.Car; /** * 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: 主管控制生成器
package refactoring_guru.builder.example.director; import refactoring_guru.builder.example.builders.Builder; 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; /** * 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: 客户端代码
package refactoring_guru.builder.example; import refactoring_guru.builder.example.builders.CarBuilder; import refactoring_guru.builder.example.builders.CarManualBuilder; import refactoring_guru.builder.example.cars.Car; import refactoring_guru.builder.example.cars.Manual; import refactoring_guru.builder.example.director.Director; /** * 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_CAR Car 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