工廠模式(Factory)


一、工廠模式介紹:

工廠模式實現了創建者和調用者的分離

工廠模式分類:

1.簡單工廠模式

2.工廠方法模式:定義一個用於創建對象的接口,讓子類決定實例化哪一個類,工廠方法使一個類的實例化延遲到其子類

​3.抽象工廠模式:提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。

面向對象設計的基本原則:

OCP(開閉原則,Open-Closed Principle):

        一個軟件的實體應當對擴展開放,對修改關閉。也就是說如果你要對一個已存在的系統做擴展的時候盡量要新增加類,而不是在原有的基礎上修改。

DIP(依賴倒轉原則,Dependence Inversion Principle)

       針對接口編程,不要針對實現編程。

LoD(迪米特法則,Law Of Demeter)

       只與你直接的朋友通信,而避免和陌生人通信。一個類盡量少的依賴其他類

 

二、工廠模式代碼實現

未使用工廠模式的情況

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//汽車接口
public  interface  Car {
     void  run();
}
//奧迪
public  class  Audi  implements  Car { 
     @Override
     public  void  run() {
         System.out.println( "奧迪在跑" );
     }
}
//比亞迪
public  class  Byd  implements  Car {
     @Override
     public  void  run() {
         System.out.println( "比亞迪在跑。" );
     }
}
//汽車測試類
public  class  TestCar { //調用者
     public  static  void  main(String[] args) {
         Car c1 =  new  Byd();
         Car c2 =  new  Audi();    
         c1.run();
         c2.run();
         //未使用工廠模式的時候,調用者會依賴很多類。違反了開閉原則
     }
}

1、簡單工廠模式:雖然能通過工廠來創建對象,但是違反了開閉原則。一旦增加功能需要在原有基礎上修改代碼。

使用了簡單工廠模式后:可以創建一個工廠類,該類中提供一個創建汽車的工廠(方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//汽車工廠
public  class  CarFactory {
     /**
      * 創建汽車
      * @param type
      * @return
      */
     public  static  Car createCar(String type){
         //該方法還會有問題,假如以后有很多汽車都需要工廠來創建。則又得修改源代碼,違反了OCP開閉原則
         if  ( "audi" .equals(type)) {
             return  new  Audi();
         } else  if  ( "byd" .equals(type)) {
             return  new  Byd();
         } else {
             return  null ;
         }
     }
}
//測試簡單工廠方法
public  class  TestSimpleFactoryCar { //調用者
     public  static  void  main(String[] args) {
         //創建汽車
         Car audi = CarFactory.createCar( "audi" ); //創建者
         Car byd = CarFactory.createCar( "byd" );
         audi.run();
         byd.run();
     }
}

2、工廠方法模式:將工廠類調整為工廠接口,需要什么類型的工廠就使用該類實現該工廠,創建相應的產品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//工廠接口
public  interface  CarFactory {
     //創建汽車方法
     Car createCar();
}
//創建比亞迪汽車的工廠
public  class  BydFactory  implements  CarFactory{
     @Override
     public  Car createCar() {
         return  new  Byd();
     }
}
//創建奧迪的工廠
public  class  AudiFactory  implements  CarFactory {
     @Override
     public  Car createCar() {
         return  new  Audi();
     }
}
 
//測試工廠方法
public  class  TestFactoryMethod {
     public  static  void  main(String[] args) {
         /**
          * 工廠方法模式好處在於,以后如果再增加一輛車。只需再實現CarFactory接口即可。避免了OCP開閉原則
          * 不用在原來的代碼上修改,只需新增類即可。
          * 例如:增加一輛奔馳,增加一個奔馳工廠BenzFactory即可。更好擴展
          */
         Car audi =  new  AudiFactory().createCar();
         Car byd =  new  BydFactory().createCar();
         audi.run();
         byd.run();
     }
}

3、抽象工廠模式:抽象工廠模式用來生產不同產品族的全部產品,對於只增加產品某一部分則不適用。抽象工廠模式是工廠模式的一種升級版本。

在有多個業務品種,業務分類時,抽象工廠能產品不同類別的一個全部產品。例如:生產汽車,抽象工廠模式可以生產高端汽車全部配件來組成一個高端汽車,

低端汽車全部配件來組成要給低端的汽車,但是不能產生一個高端的發動機和一個低端的座椅來組成一個中等的汽車。這樣會混亂。

代碼實現:

首先使用一個接口來定義一個發動機,使用具體的類來定義發動機的好壞(具體實現)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
  * 發動機接口
  */
public  interface  Engine {
     void  run();
     void  start();
}
//好的發動機
class  LuxuryEngine  implements  Engine{
     @Override
     public  void  run() {
         System.out.println( "好發動機轉的快" );
     }
     @Override
     public  void  start() {
         System.out.println( "啟動快,自動啟停" );
     }
}
//差的發動機
class  LowEngine  implements  Engine{
     @Override
     public  void  run() {
         System.out.println( "轉的慢" );
     }
     @Override
     public  void  start() {
         System.out.println( "啟動慢" );
     }
}

定義一個汽車總工廠,用來生產各種類型的汽車。所有的汽車都需要依賴此工廠來生產汽車。

1
2
3
4
5
6
7
8
/**
  *  汽車總工廠,可以創建輪胎,座椅,發動機
  */
public  interface  CarFactory {
     Engine createEngine(); //創建發動機
     Seat createSeat(); //創建座椅
     Tyre createTyre(); //創建輪胎
}

然后根據生產的不同產品,類創建具體的實現來生產汽車。例如:專門生產高端的汽車,專門生產低端的汽車。都可以用針對CarFactory具體的實現來創建。

高端汽車制造工廠,所有汽車的生產必須依賴汽車總工廠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
  *  高端汽車制造工廠
  */
public  class  LuxuryCarFactory  implements  CarFactory{
     @Override
     public  Engine createEngine() {
         return  new  LuxuryEngine();
     }
     @Override
     public  Seat createSeat() {
         return  new  LuxurySeat();
     }
     @Override
     public  Tyre createTyre() {
         return  new  LuxuryTyre();
     }
}

低端汽車制造工廠,所有汽車的生產必須依賴汽車總工廠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
  *  低端汽車制造工廠
  */
public  class  LowCarFactory  implements  CarFactory{
     @Override
     public  Engine createEngine() {
         return  new  LowEngine();
     }
     @Override
     public  Seat createSeat() {
         return  new  LowSeat();
     }
     @Override
     public  Tyre createTyre() {
         return  new  LowTyre();
     }
}

具體生產汽車的時候就可以根據需要來創建具體的汽車了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  static  void  main(String[] args) {
     //想要好車
     CarFactory factory =  new  LuxuryCarFactory();
     Engine engine = factory.createEngine(); //創建高端發動機
     engine.run();
     engine.start();
     
     //想要差一點的車
     CarFactory factory2 =  new  LowCarFactory();
     Engine e2= factory2.createEngine();
     Seat s2 = factory2.createSeat();
     Tyre t2 = factory2.createTyre();
     e2.run();
     e2.start();
     //以后想要中等車的話可以增加相應中等配件的接口
}

以上就是一個針對產品族的工廠,用來生產一個產品,而不是一個配件。假如以后想生產一個中端汽車產品。就可以增加相應的類,實現汽車總工廠CarFactory

來生產。

 

三、工廠模式要點

簡單工廠模式(靜態工廠模式)

   雖然某種程度不符合面向對象規則(不符合開閉原則,每次新增內容都需要在原有代碼上修改),但是實際使用最多。

工廠方法模式

   不修改已有類的前提下,通過增加新類來實現擴展。

抽象工廠模式

    不可以增加產品中某一個配件,可以增加一個具體的產品族。

 

四、應用場景

JDK中的Calendar的getInstance方法

JDBC中Connection對象的獲取getConnection

Hibernate中SessionFactory創建Session

spring中的IOC容器創建管理bean對象的時候也是工廠模式

XML解析時的DocumentBuilderFactory創建解析器對象

反射中Class對象的newInstance方法。

 

 

 Java23種設計模式學習筆記【目錄總貼】

參考資料:

  大話設計模式(帶目錄完整版).pdf

  HEAD_FIRST設計模式(中文版).pdf

  尚學堂_高淇_java300集最全視頻教程_【GOF23設計模式】


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM