1. 程式人生 > >淺談簡單工廠,工廠方法,抽象工廠的區別和使用

淺談簡單工廠,工廠方法,抽象工廠的區別和使用

  工廠模式是分為三種,分別是簡單工廠,工廠方法,抽象工廠。其中工廠方法和抽象工廠是GoF23種設計模式中的一種,而簡單工廠則不是一種設計模式,更加可以理解的是一種編碼時候預定俗稱的一種習慣。那麼,就在接下來三點中分別去分析理解工廠模式。

一 簡單工廠:通過例項化一個工廠類,來獲取對應的產品例項。我們不需要關注產品本身如何被建立的細節,只需要通過相應的工廠就可以獲得相應的例項。簡單工廠包括三種角色:

1.工廠:簡單工廠模式的核心,它負責實現建立所有例項的內部邏輯。工廠類的建立產品類的方法可以被外界直接呼叫,建立所需的產品物件。  

2.抽象產品 :簡單工廠模式所建立的所有物件的父類,它負責描述所有例項所共有的公共介面。

3.具體產品:是簡單工廠模式的建立目標,所有建立的物件都是充當這個角色的某個具體類的例項。

比如以下例子:

        

                            (類設計的UML圖) 

1.Drinks作為產品的抽象類並且有抽象方法produce();(抽象產品
public  abstract class Drinks {    
  protected abstract void produce();
}
2.Sprite繼承Drinks是要被具體生產出來的產品,他重寫了produce()方法。(具體產品)
public class Sprite extends Drinks {

@Override
protected void produce() {
System.out.println("drink sprite");
}
}

3.Cola同樣也繼承了Drinks,是要被生產出來的具體產品。
(具體產品)
public class Cola extends Drinks {

@Override
protected void produce() {
System.out.println("Drink Cola");
}
}

4.DrinksFactory為簡單工廠,向外暴露produceDrink方法來獲取產品的例項(工廠
public class DrinksFactory {

public Drinks produceDrink(Class className){
try {
return (Drinks) Class.forName(className.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

return null;
}
}

5.Client為應用層,Client端想要獲取到Cola或者Sprite物件,只要通過DrinkFactory中的produceDrink方法傳入相對應的對應的產品
public class Client {
public static void main(String[] args) {
DrinksFactory factory = new DrinksFactory();
Cola cola = (Cola) factory.produceDrink(Cola.class);
cola.produce();
}
}
簡單工廠的優點:
1.不需要關心類的建立細節。
2.減輕類之間的耦合依賴,具體類的實現只是依賴於簡單工廠,而不依賴其他類。

簡單工廠的缺點:
1.擴充套件複雜,當簡單工廠需要生產出另外一種產品的時候,需要擴充套件工廠的內部建立邏輯,比較有可能引起較大的故障
2.由於工廠類集中了所有例項的建立邏輯,違反了高內聚責任分配原則,將全部建立邏輯集中到了一個工廠類中


二.工廠方法

  工廠方法的定義是:定義一個建立物件的介面,讓實現這個介面的的類去決定例項化具體的類。工廠方法讓類的例項化推遲到實現介面的子類中進行。

  比如說,我現在需要一瓶可樂,有可口可樂公司生產的可樂也有百事可樂公司生產的可樂,那麼對於可樂這個產品等級(抽象工廠中會具體說明),具體生產什麼可樂並不是在一個工廠實現,而是由一個可樂工廠指定一個標準(接口裡面的抽象方法),可口可樂公司百事可樂公司只要按照這個標準去生產就可以了。   

                                               

                                             (2)工廠方法的Uml類圖 

 

1.Cola此類是產品的父類
public abstract class Cola {
protected abstract void drinks();
}
2.PepsiCola繼承Cola,是要生產的產品之一
public class PepsiCola extends  Cola {

@Override
protected void drinks() {
System.out.println("Drinks PepsiCola");
}
}
3.CoCoCola同樣繼承Cola,也是要生產的產品之一
public class CoCoCola extends Cola {

@Override
protected void drinks() {
System.out.println("Drinks cococoLa");
}
}
4.ColaFacotry定義抽象工廠,指定要生產此類產品的規範(存在的方法與屬性),指定工廠方法
public interface ColaFacotry {

Cola produce(Class<Cola> cola);
}
5.PepsiColaFactory定義子類工廠,它繼承抽象工廠,實現了對某一產品等級的產品的獲得
public class PepsiColaFactory implements ColaFacotry {

public PepsiCola produce(Class cola) {
if (cola.isInstance(PepsiCola.class)){
return new PepsiCola();
}
return null;
}
}
6.ColaFacotry,是規定工廠方法去獲得拿一些的產品等級的商品,比如說,我規定生產的產品等級是可樂和草莓可樂,那麼對於它的實現類來說,也就是其子類中的過載方法來說去具體實現獲取產品的具體實現。
public interface ColaFacotry {

Cola produce(Class<Cola> cola);
}



 

三.抽象工廠

  抽象工廠是提供了建立一系列服務的的物件的介面。那麼問題就來了,怎麼區分和工廠方法中的服務物件寧?此時就需要對一組概念有所理解,即產品等級和產品族,我從網上找到下面這張圖,進行解釋說明。在圖(4)中,我們可以通過橫向和縱向的比較,橫向是某一個手機廠商如蘋果,小米等,他們不僅僅生產手機,還生產電腦,耳機等一系類產品,那麼我們把蘋果,小米,華為這樣的廠商可以認為他們生產的是一個產品族,而他們自己本身就是一個抽象工廠的具體實現;那麼縱向來看,不管是小米華為還是蘋果,他們生產的產品是按照一定的規則來生產,顯示屏,電池,處理器等等,所以對於縱向的產品來說,他們又是屬於同一個產品等級,我們亦可以稱他們的實現為工廠方法。

  綜上所述,抽象工廠解決的是橫向的產品族,工廠方法解決的是縱向的產品等級。具體抽象工廠請看程式碼。

                 

                                              (3)產品等級和產品族(圖片來自https://laravel-china.org/topics/18598?order_by=created_at&) 

 

                          

                          (4)產品等級示意圖

   1.AbstractFactory 抽象工廠

public  interface AbstractFactory {

public Phone producePhone();

public Computer producaComputer();
}
2.AppleFactory具體工廠的實現一
public class AppleFactory implements AbstractFactory {
public Phone producePhone() {
return new Iphone();
}

public Computer producaComputer() {
return new Mac();
}
}
3.MiFactory具體工廠的實現二
public class MiFactory implements AbstractFactory {
public Phone producePhone() {
return new MiPhone();
}

public Computer producaComputer() {
return new MiComputer();
}
}
4.Phone抽象產品等級一
public abstract class Phone {
public abstract void call();
}
5.Iphone具體產品一
public class Iphone extends Phone {

@Override
public void call() {
System.out.println("Iphone call");
}
}
6.MiPhone具體產品一
public class MiPhone extends Phone {

@Override
public void call() {
System.out.println("Mi Phone call");
}
}
7.Computer抽象產品等級二
public  abstract class Computer {

public abstract void work();
}
8.Mac具體產品一
public class Mac extends Computer {

@Override
public void work() {
System.out.println("MAC work");
}
}
9.MiComputer 具體產品二

public class MiComputer extends Computer {

@Override
public void work() {
System.out.println("MI computer word");
}
}
10.客戶端
public class Clint {

public static void main(String[] args) {
AppleFactory appleFactory = new AppleFactory();
appleFactory.producaComputer().work();
appleFactory.producePhone().call();

MiFactory miFactory = new MiFactory();
miFactory.producaComputer().work();
miFactory.producePhone().call();
}
}

 

      

                        (5)抽象工廠UML類圖

從UML類圖中不難看出,我們如果需要拓展抽象工廠裡面的方法會比較麻煩,因為我們必須修改抽象類以及新增對應的產品等級,這樣修改量比較大,但是每種產品之間相互解耦,符合程式設計的“高內聚低耦合”的思想。

 

最後,不管是抽象工廠還是工廠方法甚至是簡單工廠,他們的存在都有一定的優缺點,在設計程式的時候要根據具體情況進行取捨,不存在那種設計好那種設計特別差,只是針對不同的業務場景的不一樣的處理。