淺談簡單工廠,工廠方法,抽象工廠的區別和使用
工廠模式是分為三種,分別是簡單工廠,工廠方法,抽象工廠。其中工廠方法和抽象工廠是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類圖中不難看出,我們如果需要拓展抽象工廠裡面的方法會比較麻煩,因為我們必須修改抽象類以及新增對應的產品等級,這樣修改量比較大,但是每種產品之間相互解耦,符合程式設計的“高內聚低耦合”的思想。
最後,不管是抽象工廠還是工廠方法甚至是簡單工廠,他們的存在都有一定的優缺點,在設計程式的時候要根據具體情況進行取捨,不存在那種設計好那種設計特別差,只是針對不同的業務場景的不一樣的處理。