生成器設計模式(學習筆記)

  1. 意圖

  將一個複雜對象的建立與它的表示分離,使得一樣的建立過程能夠建立不一樣的表示java

  2. 動機

  • 軟件系統中,有時候面臨着一個複雜對象的建立工做,一般由各個部分的子對象用必定的算法構成;因爲需求的變化,這個複雜對象的各個部分常常面臨着劇烈的變化,可是將他們組合在一塊兒的算法相對穩定
  • 如何應對這種變化?如何提供一種封裝機制來隔離出複雜對象的各個部分的變化,從而保持系統中的穩定構建算法不隨需求改變而改變

  3. 適用性

  • 使用生成器可避免重疊構造函數(telescopic constructor)的出現

  假設構造函數中有十個可選參數,那麼調用該函數會很是不方便;所以,須要重載這個構造函數,新建幾個只有較少參數的簡化版。可是這些構造函數仍需調用主構造函數,傳遞一些默認數值來代替省略掉的參數算法

class Pizza {
    Pizza(int size) { ... }
    Pizza(int size, boolean cheese) { ... }
    Pizza(int size, boolean cheese, boolean pepperoni) { ... }
    // ...
  • 當建立複雜對象的算法應該獨立於該對象的組成部分以及他們的裝配方式時
  • 當構造過程必須容許被構造對象有不一樣的表示時

  4. 結構

 

  5. 效果

  1) 能夠改變一個產品的內部表示 Builder對象提供給導向器一個構造產品的抽象接口,產品是經過抽象接口構造的。該接口使得生成器能夠隱藏這個產品的表示和內部結構。當時須要改變產品的內部結構,只須要定義一個新的生成器app

  2) 將構造代碼和表示代碼分開 Builder模式經過封裝一個複雜對象的建立和表示方式提升了對象的模塊性。每一個Concretebuilder包含了建立和裝配一個特定產品的全部代碼。Director能夠複用它以在相同部件集合的基礎上構建不一樣的productide

  3)對構造過程進行更精細的控制 Builder模式是在導向器的控制下,一步一步構造產品的。僅當產品完成時,導向器才從生成器中取回它。所以,builder接口相比其餘建立型模式能更好的反映產品的構造過程,這使咱們能夠更精細的控制構造過程函數

  6. 代碼實現

  Builers 

  builders/Builder.java: 通用生成器接口ui

package builder.builders;

import builder.cars.CarType;
import builder.components.Engine;
import builder.components.GPSNavigator;
import builder.components.Transmission;
import builder.components.TripComputer;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:58
 * 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: 汽車生成器this

package builder.builders;

import builder.cars.Car;
import builder.cars.CarType;
import builder.components.Engine;
import builder.components.GPSNavigator;
import builder.components.Transmission;
import builder.components.TripComputer;

/**
 * @author GaoMing
 * @date 2021/7/18 - 10:01
 */
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: 汽車手冊生成器spa

 

package builder.builders;

import builder.cars.CarType;
import builder.cars.Manual;
import builder.components.Engine;
import builder.components.GPSNavigator;
import builder.components.Transmission;
import builder.components.TripComputer;

/**
 * @author GaoMing
 * @date 2021/7/18 - 10:03
 * 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: 汽車產品3d

package builder.cars;

import builder.components.Engine;
import builder.components.GPSNavigator;
import builder.components.Transmission;
import builder.components.TripComputer;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:48
 * 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: 手冊產品code

package builder.cars;

import builder.components.Engine;
import builder.components.GPSNavigator;
import builder.components.Transmission;
import builder.components.TripComputer;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:56
 * 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 builder.cars;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:51
 */
public enum CarType {
    CITY_CAR, SPORTS_CAR, SUV
}

  Components

  components/Engine.java: 產品特徵 1

package builder.components;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:27
 * 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 builder.components;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:33
 * 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 builder.components;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:35
 * Another feature of a car
 */
public enum Transmission {
    SINGLE_SPEED, MANUAL, AUTOMATIC, SEMI_AUTOMATIC
}

  components/TripComputer.java: 產品特徵 4  

package builder.components;

import builder.cars.Car;

/**
 * @author GaoMing
 * @date 2021/7/18 - 9:48
 * 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 builder.director;

import builder.cars.CarType;
import builder.components.Engine;
import builder.components.GPSNavigator;
import builder.components.Transmission;
import builder.components.TripComputer;
import builder.builders.Builder;

/**
 * @author GaoMing
 * @date 2021/7/18 - 10:08
 * 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 builder;

import builder.builders.CarBuilder;
import builder.builders.CarManualBuilder;
import builder.cars.Car;
import builder.cars.Manual;
import builder.director.Director;

/**
 * @author GaoMing
 * @date 2021/7/18 - 10:13
 * 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 

  7. 與其餘模式的關係

  • 生成器重點關注如何分步生成複雜對象。 抽象工廠專門用於生產一系列相關對象。 抽象工廠會立刻返回產品, 生成器則容許你在獲取產品前執行一些額外構造步驟。

  • Composite一般是由Builder生成的

  • 與其餘建立型模式不一樣,生成器不要求產品擁有通用的接口,這使得相同的建立過程生成不一樣的產品成爲可能。

  8. 已知應用

  • java.lang.StringBuilder#append() ( 非同步 )
  • java.lang.StringBuffer#append() ( 同步 )java.nio.ByteBuffer#put() (還有 Char­Buffer、 Short­Buffer、 Int­Buffer、 Long­Buffer、 Float­Buffer 和 Double­Buffer)
  • javax.swing.GroupLayout.Group#addComponent()
  • java.lang.Appendable的全部實現

  識別方法: 生成器模式能夠經過類來識別, 它擁有一個構建方法和多個配置結果對象的方法。 生成器方法一般支持方法鏈 (例如 someBuilder->setValueA(1)->setValueB(2)->create() )  

相關文章
相關標籤/搜索