Java設計模式之builder模式


Java設計模式之builder模式

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

1. builder簡介

builder模式也叫建造者模式,builder模式的作用將一個復雜對象的構建與他的表示分離,使用者可以一步一步的構建一個比較復雜的對象。

2. 代碼實例

我們通常構造一個有很多參數的對象時有三種方式:構造器重載,JavaBeans模式和builder模式。通過一個小例子我們來看一下builder模式的優勢。

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個參數,如果參數更多的話,那將是指數級增長,肯定是不合理的。要么你定義一個全部參數的構造器,使用者只能多傳入一些不需要的屬性值來匹配你的構造器。很明顯這種構造器重載的方式對於多屬性的情況是不完美的。

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方法填充屬性值。

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本身,以便可以將屬性連接起來。我們就可以像下面這樣使用了。

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

當然具體使用builder的情況肯定沒有這么簡單,但是思路大致一樣:先通過某種方式取得構造對象需要的所有參數,再通過這些參數一次性構建這個對象。比如MyBatis中SqlSessionFactoryBuilder就是通過讀取MyBatis的xml配置文件來獲取構造SqlSessionFactory所需要的參數的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM