全網最詳細的工廠設計模式,本文主要是創建型設計模式中的工廠方法和抽象工廠,先由傳統實作方式引出問題,接著對代碼改進到簡單工廠,后擴展到工廠方法,最后是抽象工廠模式,文中包括概念理解和相關實作代碼,
讀者可以拉取完整代碼本地學習,實作代碼均測驗通過上傳到碼云
一、引出問題
如果有一個客戶老王,需要購買產品,產品分別是A、B、C,
如果用傳統方法實作,分別定義A、B、C三個類,再分別創建他們所屬的方法,
在客戶物件中再分別呼叫他們的方法,
Product ClientProduct(String orderType) {
Product product;
if (orderType.equals("A")) {
product = new ProductA();
} else if (orderType.equals("B")) {
product = new ProductB();
} else if (orderType.equals("B")) {
product = new ProductC();
}
// product制作程序
product.common();
return product;
}
如果我們需要再增加一個產品D,就需要判斷再增加一個分支,然后在分支里面創建產品物件,呼叫產品D的方法,
這樣代碼的維護性是極差的,查看我們的軟體設計七大原則,很明顯,這違反了開閉原則、依賴倒置原則.
如果又有個客戶小王,那么小王也必須依賴每個產品類,這樣就顯得冗雜,
二、簡單工廠(靜態工廠)
簡單工廠(靜態工廠)模式就應用而生了,
如果我們將產品A、B、C抽象出來一個父類,再專門創建一個工廠類,在客戶購買產品時,只需要傳入產品的型別,由工廠去創建產品,
簡單工廠模式中包含如下角色:
Factory:工廠角色
? 工廠角色負責實作創建所有實體的內部邏輯,
Product:抽象產品角色
? 抽象產品角色是所創建的所有物件的父類,負責描述所有實體所共有的公共介面,
ConcreteProduct:具體產品角色
? 具體產品角色是創建目標,所有創建的物件都充當這個角色的某個具體類的實體,
看看我們對原始實作方式后的代碼,
產品抽象父類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class Product {
public void common(){
System.out.println("這是產品父類公共方法...");
}
}
產品A:
/**
* @author tcy
* @Date 28-07-2022
*/
public class ProductA extends Product{
public void common(){
System.out.println("這是產品A方法...");
}
}
產品B:
/**
* @author tcy
* @Date 28-07-2022
*/
public class ProductB extends Product{
public void common(){
System.out.println("這是產品B方法...");
}
}
工廠類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class SimpleFactory {
public Product createProduct(String orderType) {
Product product = null;
if (orderType.equals("A")) {
product = new ProductA();
} else if (orderType.equals("B")) {
product = new ProductB();
} else if (orderType.equals("C")) {
product = new ProductC();
}
return product;
}
}
客戶老王類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class Client {
SimpleFactory simpleFactory;
public Client(SimpleFactory simpleFactory) {
this.simpleFactory = simpleFactory;
}
public Product orderProduct(String orderType) {
Product product;
product = simpleFactory.createProduct(orderType);
//呼叫每個產出相應的方法
product.common();
System.out.println(product.getClass());
return product;
}
public static void main(String[] args) {
Client client=new Client(new SimpleFactory());
client.orderProduct("A");
}
}
這樣簡單工廠模式就實作了,這樣的話老王和具體的產品就很好的解耦了,也不需要老王再依賴具體產品類,依賴倒置問題就很好的解決了,
如果增加一個產品D,需要再重新定義一個D類,實作product介面,而后在工廠類中增加一個分支結構,
顯而易見這樣實作,缺陷依然存在:
1、工廠類集中了所有產品創建邏輯,職責過重,一旦發生例外,整個系統將受影響,
2、使用簡單工廠模式將會增加系統中類的個數,在一定程式上增加了系統的復雜度和理解難度,
3、系統擴展困難,一旦增加新產品不得不修改工廠邏輯,在產品型別較多時,可能造成邏輯過于復雜,
4、簡單工廠模式由于使用了靜態工廠方法,造成工廠角色無法形成基于繼承的等級結構,
這種方法只是一種編碼方式,并不輸入設計模式的一種,且局限于產品種類較少,
三、工廠方法
在簡單工廠中老王需要具體的產品,就在他自己的類中去創建需要的產品,老王雖然不依賴具體產品,但老王現在需要依賴工廠實作類了,
簡單工廠是將產品類抽象化,具體的產品由工廠類去實作,
如果我們將工廠類也抽象化,那就引出了我們今天第一個設計模式——工廠方法,
工廠方法有四個角色:
1、抽象工廠(Abstract Factory):提供了創建產品的介面,呼叫者通過它訪問具體工廠的工廠方法 createProduct() 來創建產品,
2、具體工廠(ConcreteFactory):主要是實作抽象工廠中的抽象方法,完成具體產品的創建,
3、抽象產品(Product):定義了產品的規范,描述了產品的主要特性和功能,
4、具體產品(ConcreteProduct):實作了抽象產品角色所定義的介面,由具體工廠來創建,它同具體工廠之間一一對應,
我們對簡單工廠代碼進行改造,
抽象產品父類、產品A類、產品B類保持不變,重點看工廠類
抽象工廠類:
/**
* @author tcy
* @Date 28-07-2022
*/
public abstract class AbstractFactory {
public abstract Product createProduct(String orderType);
}
具體實作工廠A類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class ConcreteFactoryA extends AbstractFactory{
@Override
public Product createProduct(String orderType) {
System.out.println("引數為:"+orderType);
return new ProductA();
}
}
具體實作工廠B類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class ConcreteFactoryB extends AbstractFactory{
@Override
public Product createProduct(String orderType) {
return new ProductB();
}
}
老王類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class Client {
AbstractFactory simpleFactory;
public Client(AbstractFactory simpleFactory) {
this.simpleFactory = simpleFactory;
}
public Product orderProduct(String orderType) {
Product product;
product = simpleFactory.createProduct(orderType);
//呼叫每個產出相應的方法
product.common();
System.out.println(product.getClass());
return product;
}
public static void main(String[] args) {
Client client=new Client(new ConcreteFactoryA());
client.orderProduct("A");
}
}
這樣的好處就在于老王只管他要關注的抽象工廠,具體是哪個工廠實作類生產產品,老王也不需要關注,
典型的解耦框架,高層模塊只需要知道產品的抽象類,無須關心其他實作類,滿足迪米特法則、依賴倒置原則和里氏替換原則,
缺點也是顯而易見的:
- 類的個數容易過多,增加復雜度,
- 考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,
- 抽象產品只能生產一種產品,
如果對工廠方法依然一知半解的話,接著往下看工廠方法的一個典型實作
在JDK中對工廠方法有大量的運用,其中比較典型的是
new ArrayList<>().iterator();
我們知道集合的一個大分支依賴的是Collection介面,我們以ArrayList作為舉例,
Collection介面相當于產品的抽象父類,ArrayList相當于具體產品,
Iterator是一個抽象工廠,在ArrayList中有一個Itr內部類實作了Iterator介面
當我們呼叫集合的iterator()方法遍歷物件時,就會呼叫各自類的具體實作方法,
四、抽象工廠
有一天,產品A、B、C升級改造了,三種產品分別有紅色和藍色,如果還用工廠方法的話,那簡直是個災難,具體工廠實作類需要六個,
就引出我們今天的第二個設計模式——抽象工廠,
抽象工廠模式(Abstract Factory Pattern):提供一個介面,用于創建創建一系列相關或相互依賴物件的家族,而無須指定它們具體的類,抽象工廠模式又稱為Kit模式,屬于物件創建型模式,
抽象工廠模式與工廠方法模式區別在于,工廠方法模式針對的是一個產品等級結構,
而抽象工廠模式則需要面對多個產品等級結構(各種顏色),一個工廠等級結構可以負責多個不同產品等級結構(不同顏色)中的產品物件的創建 ,
抽象工廠依然是四個角色:
-
AbstractFactory:抽象工廠
-
ConcreteFactory:具體工廠
-
AbstractProduct:抽象產品
-
Product:具體產品
我們開始改造工廠方法代碼,既然是要把產品都分成一組,那理應把產品A、B、C都抽象出來,再讓工廠類去實作各個產品的不同顏色,也就是概念中的——用于創建創建一系列相關或相互依賴物件的家族,
介面看改造后的代碼:
產品抽象類:
/**
* @author tcy
* @Date 28-07-2022
*/
public interface Product {
public void common();
}
產品抽象A家族類:
/**
* @author tcy
* @Date 28-07-2022
*/
public abstract class ProductA implements Product {
public abstract void common();
}
產品抽象B家族類:
/**
* @author tcy
* @Date 28-07-2022
*/
public abstract class ProductB implements Product {
public abstract void common();
}
具體紅色產品A類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class RedProductA extends ProductA{
@Override
public void common() {
System.out.println("這是紅色的產品A");
}
}
具體藍色產品A類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class BlueProductA extends ProductA {
@Override
public void common() {
System.out.println("這是藍色的產品A");
}
}
抽象A家族工廠類:
/**
* @author tcy
* @Date 28-07-2022
*/
public interface AbstractProductFactory {
public ProductA createProduct(String orderType);
}
實作A家族工廠類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class ConcreateProductAFactory implements AbstractProductFactory{
@Override
public ProductA createProduct(String orderType) {
return new BlueProductA();
}
}
老王類:
/**
* @author tcy
* @Date 28-07-2022
*/
public class Client {
ConcreateProductAFactory simpleFactory;
public Client(ConcreateProductAFactory simpleFactory) {
this.simpleFactory = simpleFactory;
}
public ProductA orderProduct(String orderType) {
ProductA product;
product = simpleFactory.createProduct(orderType);
//呼叫每個產出相應的方法
product.common();
System.out.println(product.getClass());
return product;
}
public static void main(String[] args) {
Client client=new Client(new ConcreateProductAFactory());
client.orderProduct("A");
}
}
這樣的話,每天工廠類可以把A的產品家族類(紅、藍)都實作,抽象工廠模式隔離了具體類的生成,使得老王并不需要知道什么產品被創建,從具體的產品解耦出來,
- 當一個產品族中的多個物件被設計成一起作業時,它能夠保證客戶端始終只使用同一個產品族中的物件,
如果要增加新產品、和新工廠很容易,如果再增加一個等級(顏色)代碼修改起來就很痛苦了,
抽象工廠模式在Spring中有大量的運用,
比較典型的是,BeanFactory 是用于管理 Bean 的一個工廠,所有工廠都是 BeanFactory 的子類,這樣我們可以通過 IOC 容器來管理訪問 Bean,根據不同的策略呼叫 getBean() 方法,從而獲得具體物件,
BeanFactory 的子類主要有
ClassPathXmlApplicationContext、
XmlWebApplicationContext、
StaticWebApplicationContext、
StaticApplicationContext,
在 Spring 中,DefaultListableBeanFactory 實作了所有工廠的公共邏輯,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/501123.html
標籤:其他
