✅ 建造者模式用於構建複雜的不可變的對象java
其實上面這句話就是建造者模式的靈魂,複雜的對象,例如擁有不少成員變量的類,咱們假設讓它不可變,咱們須要聲明變量屬性是final的,而且咱們須要用多個構造函數去設置這些變量值,例如安全
/** * Created by cuishifeng on 2018/5/31. */ public class Food { private final String apple; private final String banana; private final String pear; private final String grape; public Food(String apple){ this(apple,""); } public Food(String apple,String banana){ this(apple,banana,""); } public Food(String apple,String banana,String pear){ this(apple,banana,pear,""); } public Food(String apple,String banana,String pear,String grape){ this.apple =apple; this.banana = banana; this.pear = pear; this.grape = grape; } }
創建一個只須要所需屬性做爲參數的構造函數,爲類的成員變量賦值,這樣能夠建立一個不可變類,可是對於成員變量不少的時候,這樣的劣勢就會凸顯,咱們須要創建各類各樣的構造函數去知足需求。app
咱們遵循javaBeans約定,有一個無參構造函數,每一個成員變量都有對應的getter和setter方法框架
/** * Created by cuishifeng on 2018/5/31. */ public class Food2 { private String apple; private String banana; private String pear; private String grape; public String getApple() { return apple; } public void setApple(String apple) { this.apple = apple; } public String getBanana() { return banana; } public void setBanana(String banana) { this.banana = banana; } public String getPear() { return pear; } public void setPear(String pear) { this.pear = pear; } public String getGrape() { return grape; } }
使用這種方式對象是一直都處於可變狀態,不管咱們實例化對象後任什麼時候候調用setter方法均可以改變這個對象ide
💡 產品 💻 建造者函數
這兩個是必須的,建造者抽象接口和指揮者都是能夠省略的。工具
咱們按照最詳細的建造者模式去生產一輛小汽車,小汽車組成定義爲 底盤、方向盤、車胎這三部分,咱們爲其打造一個建造者ui
🎨 產品this
/** * Created by cuishifeng on 2018/5/30. */ public class Car { // 汽車底盤 private String chassis; // 汽車輪胎 private String steering; // 汽車座椅 private String seat; public String getChassis() { return chassis; } public String getSteering() { return steering; } public String getSeat() { return seat; } public void setChassis(String chassis) { this.chassis = chassis; } public void setSteering(String steering) { this.steering = steering; } public void setSeat(String seat) { this.seat = seat; } }
🎨 建造者抽象接口日誌
/** * Created by cuishifeng on 2018/5/30. */ public abstract class Builder { public abstract void buildChassis(String chassis); public abstract void buildSeat(String seat); public abstract void buildSteering(String steering); public abstract Car create(); }
🎨 實際的汽車建造者
/** * Created by cuishifeng on 2018/5/30. */ public class CarBuilder extends Builder { private Car car = new Car(); public void buildChassis(String chassis) { car.setChassis(chassis); } public void buildSeat(String seat) { car.setSeat(seat); } public void buildSteering(String steering) { car.setSteering(steering); } public Car create() { return this.car; } }
🎨 指揮者
/** * Created by cuishifeng on 2018/5/30. */ public class Director { Builder builder = null; public Director(Builder builder){ this.builder = builder; } public Car createCar(String chassis,String seat,String steering){ builder.buildChassis(chassis); builder.buildSeat(seat); builder.buildSteering(steering); return builder.create(); } }
開始建造汽車
/** * Created by cuishifeng on 2018/5/30. */ public class Test { public static void main(String[] args) { Builder builder = new CarBuilder(); Director director = new Director(builder); Car car1 = director.createCar("德國汽車底盤","發過進口座椅","中國輪胎"); System.out.println(car1.toString()); // 若是不使用指揮者 builder.buildSteering("中國輪胎"); builder.buildSeat("中國座椅"); builder.buildChassis("中國底盤"); Car car2 = builder.create(); System.out.println(car2.toString()); } }
✅ 使用建造者模式咱們絕大部分會是這樣去使用,將建造者定義爲內部靜態類
/** * Created by cuishifeng on 2018/5/30. */ public class User { private final String firstName; // required private final String lastName; // required private final int age; // optional private final String phone; // optional private final String address; // optional private User(UserBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; this.address = builder.address; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public String getPhone() { return phone; } public String getAddress() { return address; } public static class UserBuilder { private final String firstName; private final String lastName; private int age; private String phone; private String address; public UserBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public UserBuilder age(int age) { this.age = age; return this; } public UserBuilder phone(String phone) { this.phone = phone; return this; } public UserBuilder address(String address) { this.address = address; return this; } public User build() { return new User(this); } } }
/** * Created by cuishifeng on 2018/5/30. */ public class Test { public static void main(String[] args) { User user = new User.UserBuilder("Jhon", "Doe") .address("北京") .age(20) // .phone("123456") .build(); User user2 = new User.UserBuilder("Jhon", "Doe") .address("北京") .age(20) .phone("123456") .build(); System.out.println(user.hashCode()); System.out.println(user2.hashCode()); } }
咱們能夠爲產品制定一個額外的固定的能夠重複使用的模板,例如咱們orm框架自定義查詢中每一個自定義查詢都要用到 分頁、頁面大小、排序等等,咱們還有好多想法能夠融入到模板中去,這一次,咱們仍是去組裝汽車,而後咱們每一次裝訂汽車可能須要到的工具和說明總結。
產品模板類
/** * Created by cuishifeng on 2018/5/30. */ public class CustomeTemplate { protected String tool; protected String log; public String getTool() { return tool; } public String getLog() { return log; } }
建造者模板類
/** * Created by cuishifeng on 2018/5/30. */ public class CustomeBuilderTemplate <T extends CustomeTemplate> { protected T object; protected CustomeBuilderTemplate(T object){ this.object = object; this.object.tool = object.tool; this.object.log = object.log; } public CustomeBuilderTemplate<T> setTool(String tool){ if (!Objects.isNull(tool) && !"".equals(tool)){ this.object.tool = tool; } return this; } public CustomeBuilderTemplate<T> setLog(String log){ if (!Objects.isNull(log) && !"".equals(log)){ this.object.log = log; } return this; } public T build(){ return object; } }
/** * Created by cuishifeng on 2018/5/30. */ public class Car extends CustomeTemplate{ private String brand; private String steering; private String color; public String getBrand() { return brand; } public String getSteering() { return steering; } public String getColor() { return color; } @Override public String toString() { return "Car{" + "tool='" + tool + '\'' + ", log='" + log + '\'' + ", brand='" + brand + '\'' + ", steering='" + steering + '\'' + ", color='" + color + '\'' + '}'; } public static class CarBuilder extends CustomeBuilderTemplate<Car>{ private CarBuilder(){ super(new Car()); } public static CarBuilder builder(){ return new CarBuilder(); } public CarBuilder setBrand(String brand){ if(Objects.nonNull(brand) && !"".equals(brand)){ this.object.brand = brand; } return this; } public CarBuilder setSteering(String steering){ if(Objects.nonNull(steering) && !"".equals(steering)){ this.object.steering = steering; } return this; } public CarBuilder setColor(String color){ if(Objects.nonNull(color) && !"".equals(color)){ this.object.color = color; } return this; } } }
這樣的建造這模式會功能更增強大
/** * Created by cuishifeng on 2018/5/30. */ public class CarTest { public static void main(String[] args) { Car car = Car.CarBuilder.builder() .setBrand("奔馳") .setSteering("4座") .setColor("黑色") .setLog("記錄生活日誌") .setTool("這次使用的是建造者模式") .build(); System.out.println(car.toString()); } }
一旦完成建造,調用build方法 這個對象就不可變了。