簡(jiǎn)介
本文介紹Java設(shè)計(jì)模式中創(chuàng)建型模式的五種
一、工廠模式
工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
工廠模式提供了一種將對(duì)象的實(shí)例化過程封裝在工廠類中的方式。通過使用工廠模式,可以將對(duì)象的創(chuàng)建與使用代碼分離,提供一種統(tǒng)一的接口來創(chuàng)建不同類型的對(duì)象。
在工廠模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶端暴露創(chuàng)建邏輯,并且是通過使用一個(gè)共同的接口來指向新創(chuàng)建的對(duì)象。
介紹
意圖:定義一個(gè)創(chuàng)建對(duì)象的接口,讓其子類自己決定實(shí)例化哪一個(gè)工廠類,工廠模式使其創(chuàng)建過程延遲到子類進(jìn)行。
主要解決:主要解決接口選擇的問題。
何時(shí)使用:我們明確地計(jì)劃不同條件下創(chuàng)建不同實(shí)例時(shí)。
如何解決:讓其子類實(shí)現(xiàn)工廠接口,返回的也是一個(gè)抽象的產(chǎn)品。
關(guān)鍵代碼:創(chuàng)建過程在其子類執(zhí)行。
應(yīng)用實(shí)例:
- 您需要一輛汽車,可以直接從工廠里面提貨,而不用去管這輛汽車是怎么做出來的,以及這個(gè)汽車?yán)锩娴木唧w實(shí)現(xiàn)。
- Hibernate 換數(shù)據(jù)庫只需換方言和驅(qū)動(dòng)就可以。
優(yōu)點(diǎn):
- 一個(gè)調(diào)用者想創(chuàng)建一個(gè)對(duì)象,只要知道其名稱就可以了。
- 擴(kuò)展性高,如果想增加一個(gè)產(chǎn)品,只要擴(kuò)展一個(gè)工廠類就可以。
- 屏蔽產(chǎn)品的具體實(shí)現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。
缺點(diǎn):
每次增加一個(gè)產(chǎn)品時(shí),都需要增加一個(gè)具體類和對(duì)象實(shí)現(xiàn)工廠,使得系統(tǒng)中類的個(gè)數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時(shí)也增加了系統(tǒng)具體類的依賴。這并不是什么好事。
使用場(chǎng)景:
- 日志記錄器:記錄可能記錄到本地硬盤、系統(tǒng)事件、遠(yuǎn)程服務(wù)器等,用戶可以選擇記錄日志到什么地方。
- 數(shù)據(jù)庫訪問,當(dāng)用戶不知道最后系統(tǒng)采用哪一類數(shù)據(jù)庫,以及數(shù)據(jù)庫可能有變化時(shí)。
- 設(shè)計(jì)一個(gè)連接服務(wù)器的框架,需要三個(gè)協(xié)議,“POP3”、“IMAP”、“HTTP”,可以把這三個(gè)作為產(chǎn)品類,共同實(shí)現(xiàn)一個(gè)接口。
注意事項(xiàng):作為一種創(chuàng)建類模式,在任何需要生成復(fù)雜對(duì)象的地方,都可以使用工廠方法模式。有一點(diǎn)需要注意的地方就是復(fù)雜對(duì)象適合使用工廠模式,而簡(jiǎn)單對(duì)象,特別是只需要通過 new 就可以完成創(chuàng)建的對(duì)象,無需使用工廠模式。如果使用工廠模式,就需要引入一個(gè)工廠類,會(huì)增加系統(tǒng)的復(fù)雜度。
工廠模式包含以下幾個(gè)核心角色:
抽象產(chǎn)品 Abstract Product,定義了產(chǎn)品的共同接口或抽象類。它可以是具體產(chǎn)品類的父類或接口,規(guī)定了產(chǎn)品對(duì)象的共同方法。
具體產(chǎn)品 Concrete Product,實(shí)現(xiàn)了抽象產(chǎn)品接口,定義了具體產(chǎn)品的特定行為和屬性。
抽象工廠 Abstract Factory,聲明了創(chuàng)建產(chǎn)品的抽象方法,可以是接口或抽象類。它可以有多個(gè)方法用于創(chuàng)建不同類型的產(chǎn)品。
具體工廠 Concrete Factory,實(shí)現(xiàn)了抽象工廠接口,負(fù)責(zé)實(shí)際創(chuàng)建具體產(chǎn)品的對(duì)象。
案例
//將水果工廠抽象為抽象類,添加泛型T由子類指定水果類型
public abstract class FruitFactory<T extends Fruit> {
//不同的水果工廠,通過此方法生產(chǎn)不同的水果
public abstract T getFruit();
}
public class AppleFactory extends FruitFactory<Apple> {
//蘋果工廠,直接返回Apple,一步到位
@Override
public Apple getFruit() {
return new Apple();
}
}
二、抽象工廠模式
抽象工廠模式(Abstract Factory Pattern)是圍繞一個(gè)超級(jí)工廠創(chuàng)建其他工廠。該超級(jí)工廠又稱為其他工廠的工廠。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
在抽象工廠模式中,接口是負(fù)責(zé)創(chuàng)建一個(gè)相關(guān)對(duì)象的工廠,不需要顯式指定它們的類。每個(gè)生成的工廠都能按照工廠模式提供對(duì)象。
抽象工廠模式提供了一種創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無需指定具體實(shí)現(xiàn)類。通過使用抽象工廠模式,可以將客戶端與具體產(chǎn)品的創(chuàng)建過程解耦,使得客戶端可以通過工廠接口來創(chuàng)建一族產(chǎn)品。
介紹
意圖:提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無需指定它們具體的類。
主要解決:主要解決接口選擇的問題。
何時(shí)使用:系統(tǒng)的產(chǎn)品有多于一個(gè)的產(chǎn)品族,而系統(tǒng)只消費(fèi)其中某一族的產(chǎn)品。
如何解決:在一個(gè)產(chǎn)品族里面,定義多個(gè)產(chǎn)品。
關(guān)鍵代碼:在一個(gè)工廠里聚合多個(gè)同類產(chǎn)品。
應(yīng)用實(shí)例:工作了,為了參加一些聚會(huì),肯定有兩套或多套衣服吧,比如說有商務(wù)裝(成套,一系列具體產(chǎn)品)、時(shí)尚裝(成套,一系列具體產(chǎn)品),甚至對(duì)于一個(gè)家庭來說,可能有商務(wù)女裝、商務(wù)男裝、時(shí)尚女裝、時(shí)尚男裝,這些也都是成套的,即一系列具體產(chǎn)品。假設(shè)一種情況(現(xiàn)實(shí)中是不存在的,但有利于說明抽象工廠模式),在您的家中,某一個(gè)衣柜(具體工廠)只能存放某一種這樣的衣服(成套,一系列具體產(chǎn)品),每次拿這種成套的衣服時(shí)也自然要從這個(gè)衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具體工廠)都是衣柜類的(抽象工廠)某一個(gè),而每一件成套的衣服又包括具體的上衣(某一具體產(chǎn)品),褲子(某一具體產(chǎn)品),這些具體的上衣其實(shí)也都是上衣(抽象產(chǎn)品),具體的褲子也都是褲子(另一個(gè)抽象產(chǎn)品)。
優(yōu)點(diǎn):當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。
缺點(diǎn):產(chǎn)品族擴(kuò)展非常困難,要增加一個(gè)系列的某一產(chǎn)品,既要在抽象的 Creator 里加代碼,又要在具體的里面加代碼。
使用場(chǎng)景:文章來源:http://www.zghlxwxcb.cn/news/detail-603904.html
- QQ 換皮膚,一整套一起換。
- 生成不同操作系統(tǒng)的程序。
注意事項(xiàng):產(chǎn)品族難擴(kuò)展,產(chǎn)品等級(jí)易擴(kuò)展。
抽象工廠模式包含以下幾個(gè)核心角色:
抽象工廠(Abstract Factory):聲明了一組用于創(chuàng)建產(chǎn)品對(duì)象的方法,每個(gè)方法對(duì)應(yīng)一種產(chǎn)品類型。抽象工廠可以是接口或抽象類。
具體工廠(Concrete Factory):實(shí)現(xiàn)了抽象工廠接口,負(fù)責(zé)創(chuàng)建具體產(chǎn)品對(duì)象的實(shí)例。
抽象產(chǎn)品(Abstract Product):定義了一組產(chǎn)品對(duì)象的共同接口或抽象類,描述了產(chǎn)品對(duì)象的公共方法。
具體產(chǎn)品(Concrete Product):實(shí)現(xiàn)了抽象產(chǎn)品接口,定義了具體產(chǎn)品的特定行為和屬性。
抽象工廠模式通常涉及一族相關(guān)的產(chǎn)品,每個(gè)具體工廠類負(fù)責(zé)創(chuàng)建該族中的具體產(chǎn)品??蛻舳送ㄟ^使用抽象工廠接口來創(chuàng)建產(chǎn)品對(duì)象,而不需要直接使用具體產(chǎn)品的實(shí)現(xiàn)類。
案例
一個(gè)工廠可以生產(chǎn)同一個(gè)產(chǎn)品族的所有產(chǎn)品,這樣按族進(jìn)行分類,顯然比之前的工廠方法模式更好。
不過,缺點(diǎn)還是有的,如果產(chǎn)品族新增了產(chǎn)品,那么我就不得不去為每一個(gè)產(chǎn)品族的工廠都去添加新產(chǎn)品的生產(chǎn)方法,違背了開閉原則。
public class Router {
}
public class Table {
}
public class Phone {
}
public abstract class AbstractFactory {
public abstract Phone getPhone();
public abstract Table getTable();
public abstract Router getRouter();
}
三、單例模式
單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類提供了一種訪問其唯一的對(duì)象的方式,可以直接訪問,不需要實(shí)例化該類的對(duì)象。
單例模式是一種創(chuàng)建型設(shè)計(jì)模式,它確保一個(gè)類只有一個(gè)實(shí)例,并提供了一個(gè)全局訪問點(diǎn)來訪問該實(shí)例。
注意:
- 單例類只能有一個(gè)實(shí)例。
- 單例類必須自己創(chuàng)建自己的唯一實(shí)例。
- 單例類必須給所有其他對(duì)象提供這一實(shí)例。
介紹
意圖:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
主要解決:一個(gè)全局使用的類頻繁地創(chuàng)建與銷毀。
何時(shí)使用:當(dāng)您想控制實(shí)例數(shù)目,節(jié)省系統(tǒng)資源的時(shí)候。
如何解決:判斷系統(tǒng)是否已經(jīng)有這個(gè)單例,如果有則返回,如果沒有則創(chuàng)建。
關(guān)鍵代碼:構(gòu)造函數(shù)是私有的。
應(yīng)用實(shí)例:
- 一個(gè)班級(jí)只有一個(gè)班主任。
- Windows 是多進(jìn)程多線程的,在操作一個(gè)文件的時(shí)候,就不可避免地出現(xiàn)多個(gè)進(jìn)程或線程同時(shí)操作一個(gè)文件的現(xiàn)象,所以所有文件的處理必須通過唯一的實(shí)例來進(jìn)行。
- 一些設(shè)備管理器常常設(shè)計(jì)為單例模式,比如一個(gè)電腦有兩臺(tái)打印機(jī),在輸出的時(shí)候就要處理不能兩臺(tái)打印機(jī)打印同一個(gè)文件。
優(yōu)點(diǎn):
- 在內(nèi)存里只有一個(gè)實(shí)例,減少了內(nèi)存的開銷,尤其是頻繁的創(chuàng)建和銷毀實(shí)例(比如管理學(xué)院首頁頁面緩存)。
- 避免對(duì)資源的多重占用(比如寫文件操作)。
缺點(diǎn):沒有接口,不能繼承,與單一職責(zé)原則沖突,一個(gè)類應(yīng)該只關(guān)心內(nèi)部邏輯,而不關(guān)心外面怎么樣來實(shí)例化。
使用場(chǎng)景:
- 要求生產(chǎn)唯一序列號(hào)。
- WEB 中的計(jì)數(shù)器,不用每次刷新都在數(shù)據(jù)庫里加一次,用單例先緩存起來。
- 創(chuàng)建的一個(gè)對(duì)象需要消耗的資源過多,比如 I/O 與數(shù)據(jù)庫的連接等。
注意事項(xiàng):getInstance() 方法中需要使用同步鎖 synchronized (Singleton.class) 防止多線程同時(shí)進(jìn)入造成 instance 被多次實(shí)例化。
案例
餓漢式單例
public class Singleton {
//用于引用全局唯一的單例對(duì)象,在一開始就創(chuàng)建好
private final static Singleton INSTANCE = new Singleton();
//不允許隨便new,需要對(duì)象直接找getInstance
private Singleton() {}
//獲取全局唯一的單例對(duì)象
public static Singleton getInstance(){
return INSTANCE;
}
}
懶漢式單例
public class Singleton {
//在一開始先不進(jìn)行對(duì)象創(chuàng)建
private static Singleton INSTANCE;
private Singleton() {}
//將對(duì)象的創(chuàng)建延后到需要時(shí)再進(jìn)行
public static Singleton getInstance(){
if(INSTANCE == null) {
synchronized (Singleton.class) {
//內(nèi)層還要進(jìn)行一次檢查,雙重檢查鎖定
if(INSTANCE == null) INSTANCE = new Singleton();
}
}
return INSTANCE;
}
}
四、建造者模式
建造者模式
建造者模式(Builder Pattern)使用多個(gè)簡(jiǎn)單的對(duì)象一步一步構(gòu)建成一個(gè)復(fù)雜的對(duì)象。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
一個(gè) Builder 類會(huì)一步一步構(gòu)造最終的對(duì)象。該 Builder 類是獨(dú)立于其他對(duì)象的。
介紹
意圖:將一個(gè)復(fù)雜的構(gòu)建與其表示相分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
主要解決:主要解決在軟件系統(tǒng)中,有時(shí)候面臨著"一個(gè)復(fù)雜對(duì)象"的創(chuàng)建工作,其通常由各個(gè)部分的子對(duì)象用一定的算法構(gòu)成;由于需求的變化,這個(gè)復(fù)雜對(duì)象的各個(gè)部分經(jīng)常面臨著劇烈的變化,但是將它們組合在一起的算法卻相對(duì)穩(wěn)定。
何時(shí)使用:一些基本部件不會(huì)變,而其組合經(jīng)常變化的時(shí)候。
如何解決:將變與不變分離開。
關(guān)鍵代碼:建造者:創(chuàng)建和提供實(shí)例,導(dǎo)演:管理建造出來的實(shí)例的依賴關(guān)系。
應(yīng)用實(shí)例:
- 去肯德基,漢堡、可樂、薯?xiàng)l、炸雞翅等是不變的,而其組合是經(jīng)常變化的,生成出所謂的"套餐"。
- JAVA 中的 StringBuilder。
優(yōu)點(diǎn):
分離構(gòu)建過程和表示,使得構(gòu)建過程更加靈活,可以構(gòu)建不同的表示。
可以更好地控制構(gòu)建過程,隱藏具體構(gòu)建細(xì)節(jié)。
代碼復(fù)用性高,可以在不同的構(gòu)建過程中重復(fù)使用相同的建造者。
缺點(diǎn):
如果產(chǎn)品的屬性較少,建造者模式可能會(huì)導(dǎo)致代碼冗余。
建造者模式增加了系統(tǒng)的類和對(duì)象數(shù)量。
使用場(chǎng)景:
- 需要生成的對(duì)象具有復(fù)雜的內(nèi)部結(jié)構(gòu)。
- 需要生成的對(duì)象內(nèi)部屬性本身相互依賴。
建造者模式在創(chuàng)建復(fù)雜對(duì)象時(shí)非常有用,特別是當(dāng)對(duì)象的構(gòu)建過程涉及多個(gè)步驟或參數(shù)時(shí)。它可以提供更好的靈活性和可維護(hù)性,同時(shí)使得代碼更加清晰可讀。
注意事項(xiàng):與工廠模式的區(qū)別是:建造者模式更加關(guān)注與零件裝配的順序。
案例
public class Student {
...
//一律使用建造者來創(chuàng)建,不對(duì)外直接開放
private Student(int id, int age, int grade, String name, String college, String profession, List<String> awards) {
...
}
public static StudentBuilder builder(){ //通過builder方法直接獲取建造者
return new StudentBuilder();
}
public static class StudentBuilder{ //這里就直接創(chuàng)建一個(gè)內(nèi)部類
//Builder也需要將所有的參數(shù)都進(jìn)行暫時(shí)保存,所以Student怎么定義的這里就怎么定義
int id;
int age;
int grade;
String name;
String college;
String profession;
List<String> awards;
public StudentBuilder id(int id){ //直接調(diào)用建造者對(duì)應(yīng)的方法,為對(duì)應(yīng)的屬性賦值
this.id = id;
return this; //為了支持鏈?zhǔn)秸{(diào)用,這里直接返回建造者本身,下同
}
public StudentBuilder age(int age){
this.age = age;
return this;
}
...
public StudentBuilder awards(String... awards){
this.awards = Arrays.asList(awards);
return this;
}
public Student build(){ //最后我們只需要調(diào)用建造者提供的build方法即可根據(jù)我們的配置返回一個(gè)對(duì)象
return new Student(id, age, grade, name, college, profession, awards);
}
}
}
五、原型模式
原型模式(Prototype Pattern)是用于創(chuàng)建重復(fù)的對(duì)象,同時(shí)又能保證性能。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式之一。
這種模式是實(shí)現(xiàn)了一個(gè)原型接口,該接口用于創(chuàng)建當(dāng)前對(duì)象的克隆。當(dāng)直接創(chuàng)建對(duì)象的代價(jià)比較大時(shí),則采用這種模式。例如,一個(gè)對(duì)象需要在一個(gè)高代價(jià)的數(shù)據(jù)庫操作之后被創(chuàng)建。我們可以緩存該對(duì)象,在下一個(gè)請(qǐng)求時(shí)返回它的克隆,在需要的時(shí)候更新數(shù)據(jù)庫,以此來減少數(shù)據(jù)庫調(diào)用。
介紹
意圖:用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這些原型創(chuàng)建新的對(duì)象。
主要解決:在運(yùn)行期建立和刪除原型。
何時(shí)使用:
- 當(dāng)一個(gè)系統(tǒng)應(yīng)該獨(dú)立于它的產(chǎn)品創(chuàng)建,構(gòu)成和表示時(shí)。
- 當(dāng)要實(shí)例化的類是在運(yùn)行時(shí)刻指定時(shí),例如,通過動(dòng)態(tài)裝載。
- 為了避免創(chuàng)建一個(gè)與產(chǎn)品類層次平行的工廠類層次時(shí)。
- 當(dāng)一個(gè)類的實(shí)例只能有幾個(gè)不同狀態(tài)組合中的一種時(shí)。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實(shí)例化該類更方便一些。
如何解決:利用已有的一個(gè)原型對(duì)象,快速地生成和原型對(duì)象一樣的實(shí)例。
關(guān)鍵代碼:
- 實(shí)現(xiàn)克隆操作,在 JAVA 實(shí)現(xiàn) Cloneable 接口,重寫 clone(),在 .NET 中可以使用 Object 類的 MemberwiseClone() 方法來實(shí)現(xiàn)對(duì)象的淺拷貝或通過序列化的方式來實(shí)現(xiàn)深拷貝。
- 原型模式同樣用于隔離類對(duì)象的使用者和具體類型(易變類)之間的耦合關(guān)系,它同樣要求這些"易變類"擁有穩(wěn)定的接口。
應(yīng)用實(shí)例:
- 細(xì)胞分裂。
- JAVA 中的 Object clone() 方法。
優(yōu)點(diǎn):
- 性能提高。
- 逃避構(gòu)造函數(shù)的約束。
缺點(diǎn):
- 配備克隆方法需要對(duì)類的功能進(jìn)行通盤考慮,這對(duì)于全新的類不是很難,但對(duì)于已有的類不一定很容易,特別當(dāng)一個(gè)類引用不支持串行化的間接對(duì)象,或者引用含有循環(huán)結(jié)構(gòu)的時(shí)候。
- 必須實(shí)現(xiàn) Cloneable 接口。
使用場(chǎng)景:
- 資源優(yōu)化場(chǎng)景。
- 類初始化需要消化非常多的資源,這個(gè)資源包括數(shù)據(jù)、硬件資源等。
- 性能和安全要求的場(chǎng)景。
- 通過 new 產(chǎn)生一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限,則可以使用原型模式。
- 一個(gè)對(duì)象多個(gè)修改者的場(chǎng)景。
- 一個(gè)對(duì)象需要提供給其他對(duì)象訪問,而且各個(gè)調(diào)用者可能都需要修改其值時(shí),可以考慮使用原型模式拷貝多個(gè)對(duì)象供調(diào)用者使用。
- 在實(shí)際項(xiàng)目中,原型模式很少單獨(dú)出現(xiàn),一般是和工廠方法模式一起出現(xiàn),通過 clone 的方法創(chuàng)建一個(gè)對(duì)象,然后由工廠方法提供給調(diào)用者。原型模式已經(jīng)與 Java 融為渾然一體,大家可以隨手拿來使用。
注意事項(xiàng):與通過對(duì)一個(gè)類進(jìn)行實(shí)例化來構(gòu)造新對(duì)象不同的是,原型模式是通過拷貝一個(gè)現(xiàn)有對(duì)象生成新對(duì)象的。淺拷貝實(shí)現(xiàn) Cloneable,重寫,深拷貝是通過實(shí)現(xiàn) Serializable 讀取二進(jìn)制流。文章來源地址http://www.zghlxwxcb.cn/news/detail-603904.html
案例
public class Student implements Cloneable{ //注意需要實(shí)現(xiàn)Cloneable接口
@Override
public Object clone() throws CloneNotSupportedException { //提升clone方法的訪問權(quán)限
return super.clone();
}
}
到了這里,關(guān)于【java設(shè)計(jì)模式】創(chuàng)建型模式介紹(工廠模式、抽象工廠模式、單例模式、建造者模式、原型模式)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!