開頭日常吹牛
我想大家在平時寫代碼的過程中肯定會去想這個類我怎麼寫簡潔點,或者後面容易維護些.畢竟項目一大起來,代碼量上去了以後,就算之前寫的時候有寫註釋,但回過頭來看總是需要再捋一遍,這就很浪費時間,畢竟大家都不想拿自己的下班時間來加班,程序員要懶一點好.這個時候設計模式的應用開始變得重要起來.在這裏給大家安利一點小小的設計模式
關於設計模式,社區裏已經很多人寫過,也有更清楚更詳細的介紹,總的來看,java有26種設計模式從類型上來說就有創建型,結構型.行爲型,再細分下去就是各個具體的模式了.但是常用的就那麼幾個,這其中就包括單例(我覺得這個應該是很多人第一個學會的),簡單工廠,建造者模式,這幾個算是創建型裏面比較經典的,其餘還有策略模式,適配器,裝飾者模式,也是比較常見的.
我覺得,這裏我們可以來一波小小的介紹.那我們給個平時的開發場景出來,方便大家來點假設性行爲.
開始假設性行爲
假設我現在要設計一個類,但是這個類裏面好幾個的成員變量,我不光要創建,我還要賦值.那這個,簡單啊,老夫操起鍵盤就是一頓啪啪啪啪啪啪啪,一分鐘不到,我把所有的類跟成員寫完,不光如此,我還附贈了一堆方法,包括get,set,toString,equals跟hashcode,於是我得意洋洋的說一聲,搞定!
/**
* 示例類,房子
* */
public class MyHome {
private String mDoor;
private String mKitchen;
private String mToilet;
private String mBathroom;
private String mStudy;
public String getDoor() {
return mDoor;
}
public void setDoor(String mDoor) {
this.mDoor = mDoor;
}
public String getKitchen() {
return mKitchen;
}
public void setKitchen(String mKitchen) {
this.mKitchen = mKitchen;
}
public String getToilet() {
return mToilet;
}
public void setToilet(String mToilet) {
this.mToilet = mToilet;
}
public String getBathroom() {
return mBathroom;
}
public void setBathroom(String mBathroom) {
this.mBathroom = mBathroom;
}
public String getStudy() {
return mStudy;
}
public void setStudy(String mStudy) {
this.mStudy = mStudy;
}
public MyHome() {
}
public void entering() {
System.out.println("I entering in myHome");
}
}
心裏頭喊着舒服!這年頭寫代碼就是那麼暢快,全賴IntelliJ開發的IDE,哼哼非常好用,寫完一個Alt+Insert,點點就完事了.
恩好,我得意洋洋的寫完,好,我現在我要創建這個類了,於是我一個new方法,new出了對象之後,就是一次次地set賦值,給成員變量賦值需要幾個就來幾個set,如果我成員變量更多的話呢,不怕,出來就是下面這樣
恩,我的代碼很牛逼.
MyHome myHome = new MyHome();
myHome.setBackyard();
myHome.setBasement();
myHome.setBathroom();
myHome.setCourtyard();
myHome.setDoor();
myHome.setGate();
myHome.setKitchen();
myHome.setStudy();
myHome.setSwimmingPond();
myHome.setToilet();
然後,我感覺不行,要不我所有都在初始化的時候做了吧,這樣會不會比較舒服?想想又覺得自己更牛掰了.
public MyHome(String mDoor, String mGate, String mCourtyard, String mBackyard, String mSwimmingPond,
String mBasement, String mKitchen, String mToilet, String mBathroom, String mStudy) {
this.mDoor = mDoor;
this.mGate = mGate;
this.mCourtyard = mCourtyard;
this.mBackyard = mBackyard;
this.mSwimmingPond = mSwimmingPond;
this.mBasement = mBasement;
this.mKitchen = mKitchen;
this.mToilet = mToilet;
this.mBathroom = mBathroom;
this.mStudy = mStudy;
}
public MyHome() {
}
那麼問題來了,我現在發現我好像不需要對某個屬性賦值,因爲賦了也用不着,算了吧.簡單,我弄多一個構造方法,不給它賦值就完事了,好,我又創建一個了一個特殊的構造方法.
public MyHome(String mCourtyard, String mBackyard, String mSwimmingPond, String mBasement, String mKitchen) {
this.mCourtyard = mCourtyard;
this.mBackyard = mBackyard;
this.mSwimmingPond = mSwimmingPond;
this.mBasement = mBasement;
this.mKitchen = mKitchen;
}
public MyHome(String mToilet, String mBathroom, String mStudy) {
this.mToilet = mToilet;
this.mBathroom = mBathroom;
this.mStudy = mStudy;
}
或者我覺得這樣不行,一堆構造方法不好看,那可以啊,在有參的構造方法裏隨便給個數,或者賦值一個null,開心.
很好,我現在有兩個呢,三個呢,繼續隨便給數或者null?所以我要創建一個對象我要一堆的null作爲參數傳進去,那個畫面我真的不敢想象.像這樣
public class BuilderTest {
public static void main(String[] args){
MyHome myHome = new MyHome(null, "gate", null, null, null
, null, null, null, null, null);
}
}
分析
首先,這會導致冗餘的構造方法出現,如果我有10個成員變量,我就需要有無參的,還有剩下一堆隨意搭配的有參構造方法.真的是隨意搭配
其次,外部使用的時候就只需要這個對象,對外暴露的就只有類對象獲取,不需要關注其內部創建細節.也不符合類設計的原則
而現在我們的情況就像是,我買了房子後,我要自己對房子裏的一切再進行安排規劃最後入住。
換個思路
那既然這樣,我們乾脆讓售樓處瞭解我的需求,我說清楚,我只管買房子跟入住。從代碼上講也就是我不去主動控制這個類,我交由一個Builder類去創建,對外使用的時候我們就只需要new出一個Builder對象,然後調用其buildXXXMethod方法,最後一個build方法,創建這個目標類的對象
/**
* 建造者抽象類
*
* Created by wangshaobin on 7/30/18.
*/
abstract class AbsBuilder<T> {
/**
* 建造者建造後要返回的對象
* */
abstract T build();
/*
* 相關操作
* */
abstract T planningDoor();
abstract T planningKitchen();
abstract T planningToilet();
abstract T planningBathroom();
abstract T planningStudy();
}
/**
* 具體實現的建造者,核心類
* */
class HomeBuilder extends AbsBuilder{
private MyHome mMyHome = new MyHome();
@Override
MyHome build() {
return mMyHome;
}
@Override
HomeBuilder planningDoor(String door) {
mMyHome.setDoor(door);
return this;
}
@Override
HomeBuilder planningKitchen(String kitchen) {
mMyHome.setDoor(kitchen);
return this;
}
@Override
HomeBuilder planningToilet(String toilet) {
mMyHome.setDoor(toilet);
return this;
}
@Override
HomeBuilder planningBathroom(String bathroom) {
mMyHome.setDoor(bathroom);
return this;
}
@Override
HomeBuilder planningStudy(String study) {
mMyHome.setDoor(study);
return this;
}
}
/**
* 售樓處類
*
* Created by wangshaobin on 7/30/18.
*/
class HomeProvider {
/**
* 售樓處將用戶需求交給建造者,由建造者去創建房屋對象
*
* @param level 檔次
* */
static MyHome commandBuilder(String level) {
HomeBuilder homeBuilder = new HomeBuilder();
return homeBuilder
.planningBathroom(level+"浴室")
// .planningDoor(level+"門")
.planningKitchen(level+"廚房")
.planningStudy(level+"書房")
.planningToilet(level+"廁所")
.build();
}
}
上面定義了一個建造者類負責接收我的需求,這樣一來我就把我的需求告訴售樓處即可,由建造者他們幫我規劃好,我只需要拿到房子並使用房子即可,在代碼中調用如下。
MyHome myHome = HomeProvider.commandBuilder("高級");
myHome.entering();
優缺點
先說說優點
首先是易於解耦,將產品本身與產品創建過程進行解耦,可以使用相同的創建過程來得到不同的產品。也就說細節依賴抽象。
其次易於精確控制對象的創建,將複雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰
最後是易於拓展,增加新的具體建造者無需修改原有類庫的代碼,易於拓展,符合“開閉原則“。
缺點方面
建造者模式所創建的產品一般具有較多的共同點,其組成部分相似;如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制;如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
應用場景
需要生成的產品對象有複雜的內部結構,這些產品對象具備共性;隔離複雜對象的創建和使用,並使得相同的創建過程可以創建不同的產品
以上就是我對建造者模式的介紹,有什麼說得不到位的還請大家批評指正
參考資料如下,如有冒犯,麻煩私信溝通: