在現實生活中社會分工越來越細,越來越專業化。各種產品有專門的工廠生產,徹底告別了自給自足的小農經濟時代,這大大縮短了產品的生產週期,提高了生產效率。
同樣,在軟件開發中能否做到軟件對象的生產和使用相分離呢?
能否在滿足“開閉原則”的前提下,客戶隨意增刪或改變對軟件相關對象的使用呢?
定義
工廠(factory)模式屬於創建型模式,定義了一個創建對象的工廠接口,將產品對象的實際創建工作推遲到具體的工廠類中。
我們把被創建的對象成爲產品
,把創建產品的對象成爲工廠
如果要創建的產品不多,只要一個工廠類就可以完成,這種模式叫簡單工廠模式
,它不屬於23種設計模式,缺點是增加新產品時會違背開閉原則
工廠分類
以家電爲例,區分說明工廠模式的幾個概念
- 在還有工廠時代:如果客戶需要一臺冰箱,一般的做法是自己去造一臺冰箱,然後拿來用,也就是我們常用的通過new操作符自己創建對象實例。
- 簡單工廠模式:用戶不用自己造冰箱,會有一個工廠來幫他造海爾冰箱,想要什麼型號的海爾冰箱,這個工廠就可以建造。這個工廠就是創建海爾系列的冰箱。
- 工廠方法模式:爲了滿足客戶的需求,海爾集團的產品越來越多,有冰箱,空調,熱水器等。一個工廠無法創建所有的產品,於是單獨分出很多具體的工廠,每個工廠創建一種產品,即具體工廠只能創建一個具體的同類的產品。
- 抽象工廠模式:隨着家電的發展,出現了格力,美的等等。我們對產品再次進行分類,比如海爾的冰箱,格力的冰箱,美的的冰箱等同歸於一個工廠,都可以生產,而空調則在另外一個工廠生產。每個工廠都能生產出一組的產品來。
綜上所述:工廠模式總體分爲三類
- 簡單工廠模式(simple factory)
- 工廠方法模式(factory method)
- 抽象工廠模式(abstract factory)
三種模式從上到下逐步抽象,同時也可將工廠模式分爲兩類:工廠方法模式和抽象工廠模式。將簡單工廠模式看做爲工廠方法的一種特例。
簡單工廠模式
簡單工廠描述
簡單工廠模式又稱靜態工廠模式.它存在的目的就是定義一個用於創建對象的接口。
它的組成:
- 工廠類角色:本模式的核心,含有一定的邏輯或者判斷。由一個具體類實現。
- 抽象產品角色:是具體產品繼承的父類或者實現的接口。由抽象類或者接口來實現。
- 具體產品角色: 工廠類所創建的對象就是此角色的實例,由具體類實現。
簡單工廠實現
代碼實現如下:
/**
* 家電的接口類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 11:37
* @since 1.0.0+
*/
public interface Appliance {
/**
* 家電的描述顯示接口方法
*/
void display();
}
/**
* 型號1的冰箱
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 11:40
* @since 1.0.0+
*/
public class Refrigerator1 implements Appliance {
/**
* 冰箱1的描述顯示
*/
@Override
public void display() {
System.out.println("型號1的冰箱");
}
}
/**
* 型號2的冰箱
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 11:42
* @since 1.0.0+
*/
public class Refrigerator2 implements Appliance {
/**
* 冰箱2的描述顯示
*/
@Override
public void display() {
System.out.println("型號2的冰箱");
}
}
/**
* 家電的工廠類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 11:44
* @since 1.0.0+
*/
public class RefrigeratorFactory {
public static Appliance build(String type) {
if(type.equals("1")) {
return new Refrigerator1();
} else {
return new Refrigerator2();
}
}
}
public static void main(String[] args) {
Refrigerator refrigerator = RefrigeratorFactory.build("1");
refrigerator.display();
}
使用了簡單工廠模式後,我們不需要再關注產品創建的過程,僅僅負責獲取產品即可。
參考上面的工廠方法簡介,假如這個時候,我們需要開始生產電視,空調了,這個工廠該怎麼辦?再次打造出一個生產線,甚至重新定義產品,帶來的代價太大了,因此我們可以考慮工廠模式了。
工廠模式
工廠模式結構
工廠模式去掉了簡單工廠模式中的靜態方法,使得它可以被子類繼承。這樣在簡單工廠模式中集中在工廠方法的壓力就可以由工廠方法模式裏的不同工廠子類來分擔。
工廠模式的結構如下:
- 抽象工廠(abstract factory)角色:這是工廠模式的核心,提供創建產品的接口,調用者通過它訪問具體工廠的工廠方法來創建產品。
- 具體工廠(concrete factory)角色: 主要實現抽象工廠的抽象方法。完成具體產品的創建
- 抽象產品(product):定義了產品的規範,描述了產品的主要特徵和功能
- 具體產品(concrete product):實現了抽象產品角色所定義的接口,由具體工廠創建,同具體工廠之間一一對應。
工廠模式實現
代碼實現如下:
/**
* 家電的接口類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 11:37
* @since 1.0.0+
*/
public interface Appliance {
/**
* 家電的描述顯示接口方法
*/
void display();
}
/**
* 電視的具體實現對象
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 18:56
* @since 1.0.0+
*/
public class Television implements Appliance {
/**
* 家電的描述顯示接口方法
*/
@Override
public void display() {
System.out.println("電視");
}
}
/**
* 冰箱的具體對象
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 18:55
* @since 1.0.0+
*/
public class Refrigerator implements Appliance {
/**
* 冰箱的描述顯示接口方法
*/
@Override
public void display() {
System.out.println("冰箱");
}
}
/**
* 家電的抽象工廠接口
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 18:57
* @since 1.0.0+
*/
public interface ApplianceFactory {
/**
* 家電的生產方法接口
* @return appliance
*/
Appliance build();
}
/**
* 生產冰箱的具體工廠類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 18:59
* @since 1.0.0+
*/
public class RefrigeratorFactory implements ApplianceFactory {
/**
* 冰箱的生產方法實現
*
* @return appliance
*/
@Override
public Appliance build() {
return new Refrigerator();
}
}
/**
* 生產電視的具體工廠類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 19:00
* @since 1.0.0+
*/
public class TelevisionFactory implements ApplianceFactory {
/**
* 電視的生產方法實現
*
* @return appliance
*/
@Override
public Appliance build() {
return new Television();
}
}
public static void main(String[] args) {
ApplianceFactory refrigeratorFactory = new RefrigeratorFactory();
Appliance refrigerator = refrigeratorFactory.build();
ApplianceFactory televisionFactory = new TelevisionFactory();
Appliance television = televisionFactory.build();
refrigerator.display();
television.display();
}
抽象工廠方法
抽象工廠模式描述
隨着家電市場的擴大,出現了很多品牌的家電,比如海爾,格力等等,工廠此時也接到了更多的訂單,比如生產海爾的電視,冰箱,格力的電視,冰箱等,我們此時就需要對業務線再次進行升級,於是用到了抽象工廠方法。
首先認識下什麼是產品族:位於不同產品等級結構中,功能相關聯的產品組成的家族。比如海爾的電視和海爾的冰箱都屬於海爾品牌的家電,格力的電視和格力冰箱都屬於格力品牌的家電。
抽象工廠模式和工廠方法的區別在於需要創建對象的複雜程度上。抽象工廠模式是三個裏面最爲抽象的,最具一般性的,抽象工廠模式的定義爲:是一種爲訪問類提供一個創建一組相關或者相互依賴對象的接口,且訪問類無須指定所要產品的具體類就能得到同族的不同等級的產品的模式結構。
要使用抽象工廠模式,一般需要滿足以下條件:
- 系統中有多個產品族,每個具體工廠創建同一族但屬於不同等級結構的產品。
- 系統一次只可能消費其中某一族產品,即同族的產品一起使用。
抽象工廠模式結構
抽象工廠模式的主要角色如下:
- 抽象工廠(abstract factory):提供了創建產品的接口,包含了多個創建產品的方法,可以創建多個不同等級的產品。
- 具體工廠(concrete factory):主要實現抽象工廠中的多個抽象方法,完成具體產品的創建
- 抽象產品(product):定義了產品的規範,描述了產品的主要特徵和功能,抽象工廠模式有多個抽象產品.
- 具體產品(concrete product):實現了抽象產品角色定義的接口,由具體工廠來創建,同具體工廠之間是多對一的關係。
抽象工廠模式實現
具體實現如下:
/**
* 電視的抽象接口類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/16 11:49
* @since 1.0.0+
*/
public interface Television {
/**
* 電視的描述顯示接口方法
*/
void display();
}
/**
* 冰箱的接口類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/16 11:49
* @since 1.0.0+
*/
public interface Refrigerator {
/**
* 冰箱的描述顯示接口方法
*/
void display();
}
/**
* 家電的抽象工廠接口
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 18:57
* @since 1.0.0+
*/
public interface ApplianceFactory {
/**
* 電視的生產方法接口
* @return appliance
*/
Television buildTelevision();
/**
* 冰箱的生產方法接口
* @return appliance
*/
Refrigerator buildRefrigerator();
}
/**
* 格力冰箱的具體產品對象
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/16 11:48
* @since 1.0.0+
*/
public class GeliRefrigerator implements Refrigerator {
/**
* 格力冰箱的描述顯示接口方法
*/
@Override
public void display() {
System.out.println("格力冰箱");
}
}
/**
* 格力電視的具體產品對象
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/16 11:48
* @since 1.0.0+
*/
public class GeliTelevision implements Television {
/**
* 格力電視的描述顯示接口方法
*/
@Override
public void display() {
System.out.println("格力電視");
}
}
/**
* 海爾冰箱的具體產品對象
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/16 11:48
* @since 1.0.0+
*/
public class HaierRefrigerator implements Refrigerator {
/**
* 海爾冰箱的描述顯示接口方法
*/
@Override
public void display() {
System.out.println("海爾冰箱");
}
}
/**
* 海爾電視的具體產品對象
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/16 11:48
* @since 1.0.0+
*/
public class HaierTelevision implements Television {
/**
* 電視的描述顯示接口方法
*/
@Override
public void display() {
System.out.println("海爾電視");
}
}
/**
* 海爾家電的具體工廠類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 18:59
* @since 1.0.0+
*/
public class HaierFactory implements ApplianceFactory {
/**
* 海爾電視的生產方法接口
*
* @return appliance
*/
@Override
public Television buildTelevision() {
return new HaierTelevision();
}
/**
* 海爾冰箱的生產方法接口
*
* @return appliance
*/
@Override
public Refrigerator buildRefrigerator() {
return new HaierRefrigerator();
}
}
/**
* 格力家電的具體工廠類
*
* @author Jonathan
* @version 1.0.0
* @date 2019/8/14 18:59
* @since 1.0.0+
*/
public class GeliFactory implements ApplianceFactory {
/**
* 格力電視的生產方法接口
*
* @return appliance
*/
@Override
public Television buildTelevision() {
return new GeliTelevision();
}
/**
* 格力冰箱的生產方法接口
*
* @return appliance
*/
@Override
public Refrigerator buildRefrigerator() {
return new GeliRefrigerator();
}
}
public static void main(String[] args) {
ApplianceFactory haierFactory = new HaierFactory();
ApplianceFactory geliFactory = new GeliFactory();
Television haierTel = haierFactory.buildTelevision();
Refrigerator haierRe = haierFactory.buildRefrigerator();
Television geliTel = geliFactory.buildTelevision();
Refrigerator geliRe = geliFactory.buildRefrigerator();
haierTel.display();
haierRe.display();
geliTel.display();
geliRe.display();
}