Java設計模式之builder模式

Java設計模式之builder模式

今天學mybatis的時候,知道了SQLSessionFactory使用的是builder模式來生成的。再次整理一下什麼是builder模式以及應用場景。java

1. builder簡介

builder模式也叫建造者模式,builder模式的做用將一個複雜對象的構建與他的表示分離,使用者能夠一步一步的構建一個比較複雜的對象。設計模式

2. 代碼實例

咱們一般構造一個有不少參數的對象時有三種方式:構造器重載,JavaBeans模式和builder模式。經過一個小例子咱們來看一下builder模式的優點。mybatis

2.1 構造器重載方式

package com.wangjun.designPattern.builder;

public class Product {
    
    private int id;
    private String name;
    private int type;
    private float price;
    
    public Product() {
        super();
    }
    
    public Product(int id) {
        super();
        this.id = id;
    }

    public Product(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public Product(int id, String name, int type) {
        super();
        this.id = id;
        this.name = name;
        this.type = type;
    }

    public Product(int id, String name, int type, float price) {
        super();
        this.id = id;
        this.name = name;
        this.type = type;
        this.price = price;
    }

}

使用構造器重載咱們須要定義不少構造器,爲了應對使用者不一樣的需求(有些可能只須要id,有些須要id和name,有些只須要name,......),理論上咱們須要定義2^4 = 16個構造器,這只是4個參數,若是參數更多的話,那將是指數級增加,確定是不合理的。要麼你定義一個所有參數的構造器,使用者只能多傳入一些不須要的屬性值來匹配你的構造器。很明顯這種構造器重載的方式對於多屬性的狀況是不完美的。ui

2.2 JavaBeans方式

package com.wangjun.designPattern.builder;

public class Product2 {
    
    private int id;
    private String name;
    private int type;
    private float price;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }

}

JavaBeans方式就是提供setter方法,在使用的時候根據需求先調用無參構造器再調用setter方法填充屬性值。this

Product2 p2 = new Product2();
p2.setId(10);
p2.setName("phone");
p2.setPrice(100);
p2.setType(1);

這種方式彌補了構造器重載的不足,建立實例很容易,代碼讀起來也很容易。可是,由於構造過程被分到了幾個調用中,在構造過程當中JavaBeans可能處於不一致的狀態,類沒法僅僅經過檢驗構造器參數的有效性來保證一致性。設計

2.3 builder模式

package com.wangjun.designPattern.builder;

public class Product3 {
    
    private final int id;
    private final String name;
    private final int type;
    private final float price;
    
    private Product3(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.type = builder.type;
        this.price = builder.price;
    }
    
    public static class Builder {
        private int id;
        private String name;
        private int type;
        private float price;
        
        public Builder id(int id) {
            this.id = id;
            return this;
        }
        public Builder name(String name) {
            this.name = name;
            return this;
        }
        public Builder type(int type) {
            this.type = type;
            return this;
        }
        public Builder price(float price) {
            this.price = price;
            return this;
        }
        
        public Product3 build() {
            return new Product3(this);
        }
    }

}

能夠看到builder模式將屬性定義爲不可變的,而後定義一個內部靜態類Builder來構建屬性,再經過一個只有Builder參數的構造器來生成Product對象。Builder的setter方法返回builder自己,以即可以將屬性鏈接起來。咱們就能夠像下面這樣使用了。code

Product3 p3 = new Product3.Builder()
                            .id(10)
                            .name("phone")
                            .price(100)
                            .type(1)
                            .build();

固然具體使用builder的狀況確定沒有這麼簡單,可是思路大體同樣:先經過某種方式取得構造對象須要的全部參數,再經過這些參數一次性構建這個對象。好比MyBatis中SqlSessionFactoryBuilder就是經過讀取MyBatis的xml配置文件來獲取構造SqlSessionFactory所須要的參數的。xml

相關文章
相關標籤/搜索