設計模式(六)——建造者模式

liangxingwei發表於2017-12-14

本文原創掘金:L_Sivan

建造者模式

  • 定義:將一個複雜的物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
  • 要解決的問題:看定義就看到了,首先,針對的問題是複雜物件的構建,其次,對這些複雜的構建還可以存在不同的結果。
  • 屬於建立類模式

舉個栗子

builder,看到這個詞的第一印象就是工地裡的建造者(最近剛好學校新建宿舍樓,天天見),然後嘛,工人要做的事,就是要建一棟宿舍樓,這就是構建一個複雜的物件。而建宿舍這件事的構建過程是相同的,但是新建的宿舍樓是要男女混住的,裡面的具體構造還不一樣(女生宿舍樓梯口裝攝像頭防狼賊。。),宿舍名也不一樣,所以相同的構造過程得到不同的結果,就來實現這個栗子來玩一下。 要注意到的是,這裡的明確需求,只是得到一個宿舍樓。

先用一下假設性原則,不然都體會不了這個模式的好處,我們先假設,不用這個模式要怎麼實現這個需求。 程式碼:

// 抽象宿舍類,定義宿舍樓具有的幾個屬性
public abstract class Dormitory {
	// 地基
	protected String foundation;
	// 宿舍的攝像頭
	protected String cameraOnStairway;
	// 是否需要裝攝像頭要
	protected boolean needCamera;
	// 宿舍顏色
	protected String dormitoryColor;
	public void setFoundation(String foundation) {
		this.foundation = foundation;
	}
	public void setCameraOnStairway(String cameraOnStairway) {
		if(needCamera == true){
			this.cameraOnStairway = cameraOnStairway;
		}
	}
	public void setNeedCamera(boolean needCamera) {
		this.needCamera = needCamera;
	}
	public void setDormitoryColor(String dormitoryColor) {
		this.dormitoryColor = dormitoryColor;
	}
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("這個"+this.getClass().getSimpleName()+"宿舍樓,");
		sb.append(foundation+",");
		if(needCamera == true){
			sb.append(cameraOnStairway+",");
		}else{
			sb.append("不需要裝攝像頭,");
		}
		sb.append(dormitoryColor);
		return sb.toString();
	}
}
**********
// 男生宿舍
public class ManDormitory extends Dormitory{}
// 女生宿舍
public class WomanDormitory extends Dormitory {}
***********
// 場景類
public class Client {
	public static void main(String[] args) {
		Dormitory manDormitory = new ManDormitory();
		manDormitory.setFoundation("打了一個堅實的地基");
		manDormitory.setNeedCamera(false);
		manDormitory.setCameraOnStairway("裝了一個攝像頭");
		manDormitory.setDormitoryColor("外表是酷酷的藍色");
		System.out.println(manDormitory);
		System.out.println("-------------------------------------");
		Dormitory womanDormitory = new WomanDormitory();
		womanDormitory.setFoundation("打了一個堅實的地基");
		womanDormitory.setNeedCamera(true);
		womanDormitory.setCameraOnStairway("裝了一個酷酷的攝像頭");
		womanDormitory.setDormitoryColor("外表是萌萌的粉色");
		System.out.println(womanDormitory);
	}
}
結果:
這個ManDormitory宿舍樓,打了一個堅實的地基,不需要裝攝像頭,外表是酷酷的藍色
\-------------------------------------
這個WomanDormitory宿舍樓,打了一個堅實的地基,裝了一個酷酷的攝像頭,外表是萌萌的粉色
複製程式碼

如無意外,到這裡可能就看下去了,因為這完全不是建造者模式,完全是一個new。但我問一句,如果沒看設計模式的東西,會覺得這個東西有很大很大的問題嗎?對嘛,初學者,誰新建物件不是new的,得到結果就行了,完全不考慮擴充套件。 在這裡我很想說一句話就是,設計模式和麵向物件的東西,首先要明白麵向物件六大原則出現的目的是什麼,要解決什麼問題,否則,設計模式不就成了迂腐的教規了?物件導向是為了更好的解決需求變化的問題, 然後在變化的點,採用方法去擁抱這些變化。這才是最要緊要記住一個東西。所有的設計模式或者物件導向的所有原則都是奔向這個目的而去的。 看回程式碼,在上面例子那裡我就說了,要明確清楚的是,需求,只是得到宿舍樓,所以在場景類那裡,直接new了男女兩個宿舍,也並沒有什麼問題,確實實現了需求。但是考慮到變化的情況,假如有的男生宿舍樓處於學校外圍,經常被盜,需要裝攝像頭,而有的女生宿舍處於學校中心,太安全了,不需要裝攝像頭,怎麼辦?這個就是需求變化的點,而如果使用上面那套程式碼,我們只能在場景類那裡再new物件。每出現一個不同構建過程的物件,我們就new一個,瘋狂new,問題就是這個,擴充套件性極其差。

來用一下建造者模式

// 抽象建造類
public abstract class Builder {
	protected Dormitory dormitory;
	public abstract Dormitory buildDormitory();
}
// 負責建造男生宿舍的工人
public class ManDormitoryBuilder extends Builder{
	public ManDormitoryBuilder() {
		super.dormitory = new ManDormitory();
	}
	@Override
	public Dormitory buildDormitory() {
		super.dormitory.setFoundation("打了一個堅實的地基");
		super.dormitory.setNeedCamera(false);
		super.dormitory.setCameraOnStairway("裝了一個攝像頭");
		super.dormitory.setDormitoryColor("外表是酷酷的藍色");
		return super.dormitory;
	}
}
// 負責建造女生宿舍的工人
public class WomanDormitoryBuilder extends Builder{
	public WomanDormitoryBuilder() {
		super.dormitory = new WomanDormitory();
	}
	@Override
	public Dormitory buildDormitory() {
		super.dormitory.setFoundation("打了一個堅實的地基");
		super.dormitory.setNeedCamera(true);
		super.dormitory.setCameraOnStairway("裝了一個酷酷的攝像頭");
		super.dormitory.setDormitoryColor("外表是萌萌的粉色");
		return super.dormitory;
	}
}
// 宿舍類都沒有變化,這裡就不列出來了
// 場景類
public class Client {
	public static void main(String[] args) {
		Builder manDormitoryBuilder = new ManDormitoryBuilder();
		Dormitory manDormitory = manDormitoryBuilder.buildDormitory();
		System.out.println(manDormitory);
		System.out.println("---------------");
		Builder womanDormitoryBuilder = new WomanDormitoryBuilder();
		Dormitory womanDormitory = womanDormitoryBuilder.buildDormitory();
		System.out.println(womanDormitory);
	}
}
結果:
這個ManDormitory宿舍樓,打了一個堅實的地基,不需要裝攝像頭,外表是酷酷的藍色
\--------------------
這個WomanDormitory宿舍樓,打了一個堅實的地基,裝了一個酷酷的攝像頭,外表是萌萌的粉色
複製程式碼

分析下程式碼:我們將new物件的過程封裝到builder那裡,builder類裡有個dormitory屬性,在子類builder建構函式予以實現,確保子類builder是對應的dormitory的生產物件。然後在子類builder的buildDormitory方法實現dormitory的構造過程。這麼做有什麼好處呢?我們的上層模組Client以後再面對下層模組Dormitory的變化時,就不用做出太大的改動了,比如上文中提到的新建兩種宿舍,我們可以怎麼做?可以直接在子類中過載方法buildDormitory,傳入boolean引數來控制裝不裝攝像頭,也可以直接在子類加方法,怎樣的都行(擴充套件性啥的各自考慮啦),然後我們的上層模組Client都不需要再對這個Dormitory的構建過程有很大的瞭解(迪米特法則),我們只需要在Client中做好與Builder的“交涉”即可。

後言:看了幾篇部落格,發現還是沒看書這麼好,部落格往往直接將模式交代了就沒了。還有發現一件事,就是看到有部落格下面有評論說例子不正確啥的,但是我看了之後,其實無非就是方法的實現沒有抽象好而已,而設計模式那個思想還是在那裡的。所以我提醒自己,設計模式是一種思想,是一種方法,不是API這樣的方法,API根據引數,能得到確定結果,而設計模式不是。看設計模式類的文章的時候,看到高贊或者高踩,都要看作者對這個模式的理解,沒有帶個人理解的,都是筆記(雖說我也寫了幾篇設計模式的筆記),而已。

水平有限,難免有錯,還請評論區指責下

相關文章