前言
在上一篇中我們學習了工廠模式,介紹了簡單工廠模式、工廠方法和抽象工廠模式。本篇則介紹設計模式中屬於建立型模式的建造者模式和原型模式。
建造者模式
簡介
建造者模式是屬於建立型模式。建造者模式使用多個簡單的物件一步一步構建成一個複雜的物件。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。 簡單的來說就是將一個複雜的東西抽離出來,對外提供一個簡單的呼叫,可以在同樣的構建過程建立不同的表示。和工廠模式很相似,不過相比而言更加註重元件的裝配。
這裡用一個示例來進行說明。 我們一天吃的食物有這些,煎餅、盒飯、拉麵、豆漿、牛奶和果汁。分為三餐、早餐、午餐和晚餐,餐點主要包含吃的(俗稱飯)和喝的(豆漿,果汁之類的),那麼我們可以把煎餅和豆漿作為早餐,盒飯和果汁作為午餐,這樣我們可以清楚的知道要吃早餐和午餐包含什麼食物。
首先我們定義一個食物類,有兩個屬性,吃的和喝的。
class Meal{
private String food;
private String drinks;
public String getFood() {
return food;
}
public void setFood(String food) {
this.food = food;
}
public String getDrinks() {
return drinks;
}
public void setDrinks(String drinks) {
this.drinks = drinks;
}
}
複製程式碼
定義了食物時候,我們在定義一個食物的標準介面,一份食物包含什麼,其實也就是吃的和喝的。
interface IBuilderFood{
void buildFood();
void buildDrinks();
Meal createMeal();
}
複製程式碼
食物介面定義一個吃的和一個喝的元件,然後通過**createMeal()**方法返回我們需要的食物。 那麼現在我們便可以定義一份早餐和午餐。 程式碼示例:
class Breakfast implements IBuilderFood{
Meal meal;
public Breakfast(){
meal=new Meal();
}
@Override
public void buildFood() {
meal.setFood("煎餅");
}
@Override
public void buildDrinks() {
meal.setDrinks("豆漿");
}
@Override
public Meal createMeal() {
return meal;
}
}
class Lunch implements IBuilderFood{
Meal meal;
public Lunch(){
meal=new Meal();
}
@Override
public void buildFood() {
meal.setFood("盒飯");
}
@Override
public void buildDrinks() {
meal.setDrinks("果汁");
}
@Override
public Meal createMeal() {
return meal;
}
}
複製程式碼
定義完之後,建造早餐和午餐的的過程已經完畢了。但是這並不是建造者模式,它有個核心的Director(導演者),它用來建立複雜物件的部分,對該部分進行完整的建立或者按照一定的規則進行建立。那麼這裡我們可以建立一個Director,用來建立一份餐點。至於建立的是什麼餐點,它不用知道,這一點由呼叫者來進行決定。
這裡我們就可以定義一個飯店,可以建立一份餐點,建立什麼餐點有顧客決定。 程式碼示例:
class FoodStore{
public Meal createBreakfast(IBuilderFood bf){
bf.buildDrinks();
bf.buildFood();
return bf.createMeal();
}
}
複製程式碼
建立完成這個Director之後,我們再來進行呼叫測試。
程式碼示例:
public class BuilderTest {
public static void main(String[] args) {
FoodStore foodStore=new FoodStore();
Meal meal=foodStore.createBreakfast(new Breakfast());
Meal meal2=foodStore.createBreakfast(new Lunch());
System.out.println("小明早上吃的是:"+meal.getFood()+",喝的飲料是:"+meal.getDrinks());
System.out.println("小明中午吃的是:"+meal2.getFood()+",喝的飲料是:"+meal2.getDrinks());
}
}
複製程式碼
輸出結果:
小明早上吃的是:煎餅,喝的飲料是:豆漿
小明中午吃的是:盒飯,喝的飲料是:果汁
複製程式碼
簡單的介紹了下建造者模式的運作原理,可以概況為這4點:
-
Builder:指定一個抽象的介面,規定該產品所需實現部件的建立,並不涉及具體的物件部件的建立。
-
ConcreteBuilder:需實現Builder介面,並且針對不同的邏輯,進行不同方法的建立,最終提供該產品的例項。
-
Director:用來建立複雜物件的部分,對該部分進行完整的建立或者按照一定的規則進行建立。
-
Product:示被構造的複雜物件。
使用場景: 適用一些基本元件不便,但是組合經常變化的時候。比如超市促銷的大禮包。
優點:
- 建造者獨立,易擴充套件。
- 便於控制細節風險。
缺點
- 內部結構複雜,不易於理解。
- 產品直接需要有共同點,範圍有控制。
原型模式
原型模式(Prototype Pattern)是用於建立重複的物件,同時又能保證效能。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
一般來說我們在建立物件的時候是直接建立的,但是建立該物件的代價很大的時候,重複的二次建立就有些不划算,這時我們就可以使用原型模式。 打個比方,我們都傳送過郵件,在節日的時候一般傳送的是祝福語句,在這些祝福語句中,一般除了名字不一樣之外,大部分都是一樣的。這時我們就可以利用該模式來進行相應出建立。
這裡還是用一個的簡單的示例來說明。 小明和小紅在同一天生日,然後我們需要給他們傳送郵件進行祝福,但是由於比較懶,祝福語除了名字之外都是一樣的。這時我們就可以先完成祝福語的編寫,然後克隆該祝福語,最後根據不同的名稱進行傳送。不過這裡就從簡了,只是簡單的列印下而已。
程式碼示例:
public class PrototypeTest {
public static void main(String[] args) {
Mail mail=new Mail();
mail.setMsg("生日快樂!");
Mail mail2=(Mail) mail.clone();
mail.setName("小明");
mail2.setName("小紅");
System.out.println(mail.toString());
System.out.println(mail2.toString());
}
}
class Mail implements Cloneable {
private String name;
private String msg;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
@Override
public String toString() {
return name + ":" + msg ;
}
}
複製程式碼
輸出結果:
小明:生日快樂!
小紅:生日快樂!
複製程式碼
看完原型模式的建立,是不是感覺就是和Java中克隆即為類似呢? 實際上它的核心也就是克隆。 克隆有兩種,淺克隆和深克隆,本文主要介紹的是淺克隆。 淺克隆:
在淺克隆中,如果原型物件的成員變數是值型別,將複製一份給克隆物件;如果原型物件的成員變數是引用型別,則將引用物件的地址複製一份給克隆物件,也就是說原型物件和克隆物件的成員變數指向相同的記憶體地址。 簡單來說,在淺克隆中,當物件被複制時只複製它本身和其中包含的值型別的成員變數,而引用型別的成員物件並沒有複製。 實現Cloneable介面並重寫Object類中的clone()方法;
深克隆:
在深克隆中,無論原型物件的成員變數是值型別還是引用型別,都將複製一份給克隆物件,深克隆將原型物件的所有引用物件也複製一份給克隆物件。
簡單來說,在深克隆中,除了物件本身被複制外,物件所包含的所有成員變數也將複製。 實現Serializable介面,通過物件的序列化和反序列化實現克隆,可以實現真正的深度克隆。
使用場景:
- 類初始化的時候需要消耗大量資源的時候;
- 獲取資料庫連線繁瑣的時候;
- 一個物件,有很多個修改者的時候;
優點: 1.可以提升效能;
缺點: 1.因為必須實現Cloneable 介面,所以用起來可能不太方便。
其它
音樂推薦
原創不易,如果感覺不錯,希望給個推薦!您的支援是我寫作的最大動力! 版權宣告: 作者:虛無境 部落格園出處:www.cnblogs.com/xuwujing CSDN出處:blog.csdn.net/qazwsxpcm 個人部落格出處:www.panchengming.com 原創不易,轉載請標明出處,謝謝!