設計模式-建造者模式

建造者模式

✅ 建造者模式用於構建複雜的不可變的對象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

用getter、setter

咱們遵循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());
    }
}
  • 🐛 構造器是私有的,沒法直接實例化對象
  • 💻 對象一旦構造完成,對象是不可變的,咱們只提供了getter方法
  • 🐛 更易於閱讀,編寫和維護的客戶端代碼。此外,您的類能夠保持不變,這使您的代碼更安全。

建造者模式使用模板類

咱們能夠爲產品制定一個額外的固定的能夠重複使用的模板,例如咱們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方法 這個對象就不可變了。

相關文章
相關標籤/搜索