1. 程式人生 > >設計模式之工廠模式(包含三種模式)

設計模式之工廠模式(包含三種模式)

設計模式是一套被反覆使用,多數人知曉,經過分類編目的,程式碼設計的總結,也可以說是前人的智慧結晶。學習設計模式能讓我們對一些應用場景使用相同的套路達到很好的效果,我會不定時更新一些自己對設計模式的理解的文章,從定義,實現,應用場景來說說設計模式,今天我要說的物件是工廠模式
一:定義
什麼是工廠?工廠模式是我們最常用的例項化物件模式了,是用工廠方法代替new操作的一種模式,工廠模式屬於建立型模式:物件例項化的模式,用於解耦物件的例項化過程。簡單的說工廠模式就是用來建立物件的,傳統的物件建立方法是new,有了工廠模式之後,某些特定的物件我們不需要在每個使用的地方都使用new,而是把物件的建立放在一個或者一組統一的類中,從達到解耦的目的。
二:實現
從實現上來說,工廠模式分為三種,簡單工廠模式,工廠模式,抽象工廠模式,簡單工廠模式並不屬於23中設計模式的範疇,因為它對解耦的實現不理想,同時不符合開不原則,不過簡單工廠模式是工廠模式的一種簡易實現,可以為學習工廠模式提供一個好的開端。
在展示具體的程式碼之前,我們先來說說一個類的作用,我們提供一個類,無非是希望通過這個類來幫助我們來實現一些功能,而工廠模式中生產出來的類,都具有相同的功能,只不過這個功能的具體實現可能不一樣,
1.簡單工廠模式
簡單工廠模式的設計思想非常簡單,就像一個小型的工廠,能生產幾種特定的產品,小工廠一般都很本分,不敢太冒進,只有在收到訂單(接收到指令)的時候才敢生產產品,如果要擴大業務,生產新的產品,必須對工廠進行改造,小本生意,本來就沒有太多冗餘的空間。
小工廠呢,通常是有了某種渠道,獲得了某幾種產品的生產權,然後才針對真幾種產品建立了工廠,所以,在工廠之前,產品是確定的,而且產品的型別還不能區別太大,一般是某種大類產品下的幾個分類,這樣這個工廠的很多裝置模具都可以共用,節約成本,下面我們就以程式碼的形式來體現工廠
首先,確認產品,確認產品之前,還要確認產品的型別,方便購買一些通用的裝置
我們的產品就是輪胎,每款輪胎上都有一些介紹資訊,標識當前輪胎的種類,雖然輪胎的種類很多,功能不一,但是介紹資訊的格式都一樣
abstract class Tyre{
abstract void desc();
}
//這是賓士的輪胎
class BenzTyre extends Tyre{
@Override
void desc() {
System.out.println("這是賓士的輪胎");
}
}
//這是寶馬的輪胎
class BMWTyre extends Tyre{
@Override
void desc() {
System.out.println("這是寶馬的輪胎");
}
}
//這是奧迪的輪胎
class AudiTyre extends Tyre{
@Override
void desc() {
System.out.println("這是奧迪的輪胎");
}
}
既然已經確認了訂單,那麼接下來我們可以開始建設工廠了
class TyreFactory{
public static Tyre createTyre(String TyreName){
switch (TyreName){
case "Benz":
//接受到生產賓士輪胎的指令
return new BenzTyre();
case "BMW":
//接受到生產寶馬輪胎的指令
return new BMWTyre();
case "Audi":
//接受到生產生產奧迪輪胎的指令
return new AudiTyre();
default:
return null;
}
}
}
下面模擬客戶下單,工廠生產輪胎,拿到輪胎後確認產品的過程
class Clients{
public static void main(String[] fdfd){
//工廠接到指令生產了一個賓士的輪胎
Tyre tyre=TyreFactory.createTyre("Benz");
//客戶拿到輪胎後看一下標籤
tyre.desc();
//工廠接到指令生產了一個寶馬的輪胎
tyre=TyreFactory.createTyre("BMW");
//客戶拿到輪胎後看一下標籤
tyre.desc();
//工廠接到指令生產了一個奧迪的輪胎
tyre=TyreFactory.createTyre("Audi");
//客戶拿到輪胎後看一下標籤
tyre.desc();
}
}
總結:簡單工廠模式有一定的優點,對於客戶來說,只需要下達一個指令,就可以獲取到自己需要的產品,而不用去關心產品的生產過程。但也有很明顯的缺點,就現在的工廠來說,只符合生產現有產品的要求,當有新產品新增的時候,必須對現在的工廠進行改造,改造必然需要拆裝,拆裝的過程有導致整個工廠倒塌的風險。在程式碼的角度來說,工廠模式符合里氏替代原則,在一定程度上解決了耦合問題,但是同時,它有違反了開閉原則。當一個新的產品需要被新增的時候,必須對工廠類進行改造。那麼,是否有辦法解決這個問題呢,答案當然是有的,那就是工廠模式
2.工廠模式
工廠模式是簡單工廠模式的進階版,我們知道,簡單工廠模式的主要缺點是不符合開閉原則,當新產品被新增的時候,需要更改工廠類,所以,在工廠模式中,我們專門對工廠類進行了改造。為了生產新的產品不改造工廠類,我們抽象工廠類,也就是把工廠類變成一個抽象的物件,不進行產品的生產,把產品的生產過程交給它的子類進行,當有新的產品新增的時候,只需要新增新的子類即可,不涉及已有程式碼的更改。當然,這些子類,其實也是一個工程類,只不過是只針對某一種產品的工程類,下面展示程式碼

抽象原有的工廠類,只定義應該生產的產品型別,而不再進行具體產品的生產
abstract class TyreFactory{
//提取子類必須實現的方法
abstract Tyre createTyre();
}
創造寶馬輪胎廠,只生產寶馬輪胎
class BMWTyreFactory extends TyreFactory{
//寶馬輪胎廠生產寶馬輪胎
@Override
Tyre createTyre() {
return new BMWTyre();
}
}
創造賓士輪胎廠,只生產賓士輪胎
class BenzTyreFactory extends TyreFactory{
//賓士輪胎廠生產賓士輪胎
@Override
Tyre createTyre() {
return new BenzTyre();
}
}
創造奧迪輪胎廠,只生產奧迪輪胎
class AudiTyreFactory extends TyreFactory{
//奧迪輪胎廠生產奧迪輪胎
@Override
Tyre createTyre() {
return new AudiTyre();
}
}
再看呼叫
class Clients{
public static void main(String[] fdfd){
//賓士工廠生產了一個賓士的輪胎
Tyre tyre=new BenzTyreFactory().createTyre();
//客戶拿到輪胎後看一下標籤
tyre.desc();
//寶馬工廠生產了一個寶馬的輪胎
tyre=new BMWTyreFactory().createTyre();
//客戶拿到輪胎後看一下標籤
tyre.desc();
//奧迪工廠生產了一個奧迪的輪胎
tyre=new AudiTyreFactory().createTyre();
//客戶拿到輪胎後看一下標籤
tyre.desc();
}
}
總結:工廠模式很好的解決了簡單工廠模式不符合開閉原則的缺點,在工廠模式中新增一個產品,只需要增大產品類和對應的工廠類,不會涉及原有程式碼的更改,符合開閉原則,擴充套件不會對原有的功能產生影響,同樣工廠模式也符合里氏替代原則。但是,工廠模式並不完美,我們注意到,工廠模式只能生產一個類別的產品。比如,我們上面的輪胎工廠,只能生產輪胎,如果想生產內膽呢,而且內膽和輪胎往往都是配套使用的,寶馬的輪胎不可能配用賓士的內膽,對於這種配套的產品(物件),為了不混淆,有沒有一個好的解決方案呢,答案當然是有的,那就是抽象工廠模式
3.抽象工廠模式
抽象工廠模式最重要的思想就是引入了產品族的感念,可以理解為配套或者或有關聯的一系列產品(物件),組成一個產品族,使用這個工廠不再生產單一的產品,而是生產一整套的產品,比如我們的輪胎工廠,直接生產配套的輪胎和內膽,而不用擔心賓士的輪胎用了寶馬的內膽。
那麼,我們需要新增一個新的產品:內膽,由於賓士,寶馬,奧迪的內膽都不一樣,所以要獨立建立這三種車的內膽,並且要在原來頂層工廠類中新增一個生產內膽的抽象方法,而對應的這三種車的工廠類在生產輪胎的同時要配套的生產內膽
//建立內膽產品類
abstract class Innertube{
//內膽的標籤,顯示內膽的出身資訊
abstract void innertubeDesc();
}
//賓士內膽
class BenzInnertube extends Innertube{
@Override
void innertubeDesc() {
System.out.println("這是賓士的內膽");
}
}
//寶馬內膽
class BMWInnertube extends Innertube{
@Override
void innertubeDesc() {
System.out.println("這是寶馬的內膽");
}
}
//奧迪內膽
class AudiInnertube extends Innertube{
@Override
void innertubeDesc() {
System.out.println("這是奧迪的內膽");
}
}
//工廠類的改變
abstract class Factory{
//生產輪胎的方法
abstract Tyre createTyre();
//生產內膽的方法
abstract Innertube createInnertube();
}
//賓士
class BMWFactory extends Factory{
//寶馬輪胎廠生產寶馬輪胎
@Override
Tyre createTyre() {
return new BMWTyre();
}
//寶馬輪胎廠生產寶馬內膽
@Override
Innertube createInnertube() {
return new BMWInnertube();
}
}
//寶馬
class BenzFactory extends Factory{
//賓士輪胎廠生產賓士輪胎
@Override
Tyre createTyre() {
return new BenzTyre();
}
//賓士輪胎廠生產賓士內膽
@Override
Innertube createInnertube() {
return new BenzInnertube();
}
}
//奧迪
class AudiFactory extends Factory{
//奧迪輪胎廠生產奧迪輪胎
@Override
Tyre createTyre() {
return new AudiTyre();
}
//奧迪輪胎廠生產奧迪內膽
@Override
Innertube createInnertube() {
return new AudiInnertube();
}
}
//模擬客戶下單
class Clients{
public static void main(String[] fdfd){
//向賓士工廠下一個單,生產一套賓士專用的輪胎和內膽
BenzFactory benzFactory=new BenzFactory();
//生產
Tyre tyre=benzFactory.createTyre();
Innertube innertube=benzFactory.createInnertube();
//客戶拿到輪胎後看一下標籤
tyre.desc();
innertube.innertubeDesc();

//向寶馬工廠下一個單,生產一套寶馬專用的輪胎和內膽
BMWFactory bmwFactory=new BMWFactory();
//生產
tyre=bmwFactory.createTyre();
innertube=bmwFactory.createInnertube();
//客戶拿到輪胎後看一下標籤
tyre.desc();
innertube.innertubeDesc();

//向奧迪工廠下一個單,生產一套奧迪專用的輪胎和內膽
AudiFactory audiTyreFactory=new AudiFactory();
//生產
tyre=audiTyreFactory.createTyre();
innertube=audiTyreFactory.createInnertube();
//客戶拿到輪胎後看一下標籤
tyre.desc();
innertube.innertubeDesc();
}
}
不難看出,在工廠模式的基礎上,抽象工廠模式產品族感念的出現對於生產成套的產品(有聯絡的物件)提供了很大的便利,也符合開閉原則,里氏替代原則,不過也有它的缺陷:當在產品族(頂級工廠類)中需要新增一種新的產品的時候,所有的下級工廠都要進行修改。
三:應用場景
在什麼場景下應該使用工廠模式
1.一個系統不應當依賴於產品類例項如何被建立、組合和表達的細節
  2.這個系統的產品有多於一個的產品族,而系統只消費其中某一族的產品。
  3.同屬於同一個產品族的產品是在一起使用的,這一約束必須在系統的設計中體現出來。
  4.系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於實現。