DesignPattern - 工廠模式【建立型】

歡迎關注微信公衆號:FSA全棧行動 👋java

1、工廠模式介紹

工廠模式提供了一種建立對象的最佳方式,咱們在建立對象時不會對客戶端暴露建立邏輯,而且是經過使用一個共同的接口來指向新建立的對象。微信

  • 例子:
    • 須要購買一輛車,不用管車輛如何組裝,且能夠購買不一樣類型的汽車,好比轎車、SUV、跑車,直接去 4s 店購買就行(4s 店就是工廠)
    • 工廠生產電腦,除了 A 品牌、還能夠生產 B、C、D 品牌電腦
    • 支付業務開發,會統一下單和支付接口,具體的支付實現能夠是微信、支付、銀行卡等
  • 分類:
    • 簡單工廠模式:經過傳入相關的類型來返回相應的類,這種方式比較單一,可擴展性較差。
    • 工廠方法模式:經過實現類 實現相應的方法來決定相應的返回結果,這種方式的可擴展性比較強。
    • 抽象工廠模式:基於上述兩種模式的擴展,且支持細化產品。
  • 應用場景:
    • 解耦:分離職責,把複雜對象的建立和使用的過程分開
    • 複用代碼,下降維護成本:
      • 若是對象建立複雜且多處須要用到,若是每處都進行編寫,則不少重複代碼,若是業務邏輯發生了改變,須要四處修改
      • 使用工廠模式統一建立,則只要修改工廠類便可,下降成本

提示:工廠模式適合複雜對象的建立markdown

2、工廠模式代碼實現

一、簡單工廠模式

簡單工廠能夠根據不一樣參數返回不一樣類的實例,須要專門定義一個工廠類來負責建立其餘類的實例,被建立實例一般都具備共同的父類或接口;簡單工廠又稱 靜態工廠方法,可經過類名直接調用 ,並且只須要傳入簡單的參數便可。ide

  • 核心組成
    • Factory:工廠類,簡單工廠模式的核心,它負責實現建立全部實例的內部邏輯
    • IProduct:抽象產品類,簡單工廠模式所建立的全部對象的父類,描述全部實例所共有的公共接口
    • Product:具體產品類,是簡單工廠模式的建立目標
  • 實現步驟
    • 建立抽象產品類,裏面有產品的抽象方法,由具體的產品類去實現
    • 建立具體產品類,繼承【建立抽象產品類】,並實現具體方法
    • 建立工廠類,提供一個靜態方法(createXXX)用來生產產品,只須要傳入你想要的產品標識(如:產品名稱)
  • 優勢:將對象的建立和對象自己業務處理分離,能夠下降系統的耦合度,使得二者修改起來都相對容易。
  • 缺點:工廠類的職責相對太重,增長新的產品須要修改工廠類的判斷邏輯,這一點與開閉原則是相違背的

建立抽象產品類:oop

/** * 抽象產品 * * @author GitLqr */
public interface IPay {
	/** * 下單功能 */
	void order();
}
複製代碼

建立具體產品類:微信支付

/** * 具體產品:微信支付 * * @author GitLqr */
public class WechatPay implements IPay {
	@Override
	public void order() {
		System.out.println("微信 下單");
	}
}

/** * 具體產品:支付寶支付 * * @author GitLqr */
public class AliPay implements IPay {
	@Override
	public void order() {
		System.out.println("支付寶 下單");
	}
}
複製代碼

建立工廠類:spa

/** * 工廠類 * * @author GitLqr */
public class PayFactory {
	/** * 根據參數 返回對應的支付對象 */
	public static IPay createPay(String payType) {
		switch (payType) {
		case "alipay":
			return new AliPay();
		case "wechat":
			return new WechatPay();
		default:
			return null;
		}
	}
}
複製代碼

使用:設計

public static void main(String[] args) {
    // 簡單工廠
    // IPay pay = PayFactory.createPay("alipay");
    IPay pay = PayFactory.createPay("wechat");
    pay.order();
}
複製代碼

二、工廠方法模式

工廠方法又稱 工廠模式,是對簡單工廠模式的進一步抽象化,其好處是可使系統在不修改原來代碼的狀況下引進新的產品,即知足開閉原則。經過工廠父類定義負責建立產品的公共接口,經過子類來肯定所須要建立的類型。code

  • 核心組成
    • IProduct:抽象產品類,描述全部實例所共有的公共接口
    • Product:具體產品類,實現抽象產品類的接口
    • IFactory:抽象工廠類,描述具體工廠的公共接口
    • Factory:具體工廠類,實現抽象工廠類的接口,建立具體產品對象
  • 優勢:
    • 相比簡單工廠而言,工廠方法具備更多的可擴展性和複用性,同時也加強了代碼的可讀性
    • 將類的實例化(具體產品的建立)延遲到工廠類的子類(具體工廠)中完成,即由子類來決定應該實例化哪個類
    • 符合開閉原則,增長一個產品類,只須要實現其餘具體的產品類和具體的工廠類
    • 符合單一職責原則,每一個工廠只負責生產對應的產品
    • 使用者只須要知道產品的抽象類,無須關心產品的具體實現類,知足迪米特法則、依賴倒置原則和里氏替換原則
  • 缺點:
    • 每一個產品須要有對應的具體工廠和具體產品類,即每增長一個產品,都至少會增長 2 個類
    • 使用者必須知道具體的工廠實現類

建立抽象工廠類:orm

/** * 抽象工廠類 * * @author GitLqr */
public interface IPayFactory {
	public IPay getPay();
}
複製代碼

建立具體工廠類:

/** * 具體工廠類:建立 支付寶支付 對象 * * @author GitLqr */
public class AliPayFactory implements IPayFactory {
	@Override
	public IPay getPay() {
		return new AliPay();
	}
}

/** * 具體工廠類:建立 微信支付 對象 * * @author GitLqr */
public class WechatPayFactory implements IPayFactory {
	@Override
	public IPay getPay() {
		return new WechatPay();
	}
}
複製代碼

使用:

public static void main(String[] args) {
    // 工廠方法
    // IPayFactory payFactory = new AliPayFactory();
    IPayFactory payFactory = new WechatPayFactory();
    payFactory.getPay().order();
}
複製代碼

補充:若是後續須要增長第三種支付方式,好比銀聯支付,那麼只須要再擴展出具體產品 UnionPay,以及具體工廠 UnionPayFactory 便可,而無需改動原有的類。

三、抽象工廠模式

抽象工廠模式是基於上述兩種模式的拓展,是工廠方法模式的升級版,當須要建立的產品有多個產品線時使用抽象工廠模式是比較好的選擇。

  • 背景:
    • 工廠方法模式引入工廠等級結構,解決了簡單工廠模式中工廠類職責太重的問題
    • 但工廠方法模式中每一個工廠只建立一類具體產品類的對象,後續發展可能會致使工廠類過多,所以將一些相關的具體類組成一個」具體類族「,由同一個工廠來統一輩子產,強調的是一系列相關的產品對象!!
  • 優勢:
    • 當一個產品族中的多個對象被設計成一塊兒工做時,它能保證使用方始終只使用一個產品族中的對象
  • 缺點:
    • 產品族擴展困難,要增長一個系列的某一產品,既要在抽象工廠和超級工廠類裏修改代碼,不是很符合開閉原則
    • 增長了系統的抽象性和理解難度

補充:當抽象工廠模式中每個具體工廠類只建立一個產品對象時,抽象工廠模式退化成工廠方法模式。

1)推導過程(工廠方法 --> 抽象工廠 )

假設 "產品" 如今不僅有 支付,還須要有 退款,提現 等,這時,"產品" 的【抽象產品類】和【具體產品類】將拓展爲以下所示:

支付(IPay) 退款(IRefund) 提現(ICashout)
支付寶 AliPay AliRefund AliCashout
微信 WechatPay WechatRefund WechatCashout
銀聯 UnionPay UnionRefund UnionCashout

根據 工廠方法模式 的核心要求(一種工廠 對應生成 一種產品),那麼對應的【抽象工廠類】和【具體工廠類】將拓展爲以下所示:

支付(IPayFactory) 退款(IRefundFactory) 提現(ICashoutFactory)
支付寶 AliPayFactory AliRefundFactory AliCashoutFactory
微信 WechatPayFactory WechatRefundFactory WechatCashoutFactory
銀聯 UnionPayFactory UnionRefundFactory UnionCashoutFactory

這時就會發現,嚴格按照工廠方法模式的要求會有以下弊端:

  1. 工廠類太多了,總體感受工程文件數量很冗餘
  2. 對使用者不友好,須要知道的 "工廠" 有點多

其實這些 "產品"(支付、退款、提現...)都是屬於一類(訂單相關), 所以,能夠對【抽象工廠類】進行加強,由一個【抽象工廠類】來負責生產一類 "產品",例如能夠建立 IOrderFactory,彙總 IPayFactory、IRefundFactory、ICashoutFactory 的建立方法並對它們進行取締。因而,使用了抽象工廠模式後,對應的【抽象工廠類】和【具體工廠類】將拓展爲以下所示:

支付、退款、提現(IOrderFactory)
支付寶 AliOrderFactory
微信 WechatOrderFactory
銀聯 UnionOrderFactory

注意:抽象工廠 相比 工廠方法,就是加強了抽象工廠類,同時思想上也有了重大變化,讓抽象工廠類再也不侷限於一種產品,而是一系列產品。

2)代碼實現

建立抽象產品類:

/** * 抽象產品 * * @author GitLqr */
public interface IRefund {
	/** * 退款 */
	void refund();
}
複製代碼

建立具體產品類:

/** * 具體產品:支付寶退款 * * @author GitLqr */
public class AliRefund implements IRefund {
	@Override
	public void refund() {
		System.out.println("支付寶 退款");
	}
}
/** * 具體產品:微信退款 * * @author GitLqr */
public class WechatRefund implements IRefund {
	@Override
	public void refund() {
		System.out.println("微信 退款");
	}
}
複製代碼

建立抽象工廠類【加強版】:

/** * 抽象工廠類【加強版】 * * @author GitLqr */
public interface IOrderFactory {
	IPay getPay();

	IRefund getRefund();
}
複製代碼

建立具體工廠類【加強版】:

/** * 具體工廠類:建立 支付寶 訂單相關的一系列產品功能 * * @author GitLqr */
public class AliOrderFactory implements IOrderFactory {
	@Override
	public IPay getPay() {
		return new AliPay();
	}

	@Override
	public IRefund getRefund() {
		return new AliRefund();
	}
}
/** * 具體工廠類:建立 微信 訂單相關的一系列產品功能 * * @author GitLqr */
public class WechatOrderFactory implements IOrderFactory {
	@Override
	public IPay getPay() {
		return new WechatPay();
	}

	@Override
	public IRefund getRefund() {
		return new WechatRefund();
	}
}
複製代碼

還能夠借鑑簡單工廠模式,建立一個"超級工廠類",根據不一樣參數獲取不一樣的具體工廠,方便使用者使用:

public class OrderFactoryProducer {

	public static IOrderFactory getFactory(String type) {
		switch (type) {
		case "alipay":
			return new AliOrderFactory();
		case "wechat":
			return new WechatOrderFactory();
		default:
			return null;
		}
	}
}
複製代碼

說明:【簡單工廠模式】的最大缺點就是負責了全部具體產品的建立,而這裏則不一樣,具體產品的建立已交由具體工廠去建立,"超級工廠類" 只負責找到合適的具體工廠,與產品沒有直接關係。固然,」超級工廠類「這種方式方式仍是不符合開閉原則的,需本身權衡利弊,我的感受至少比讓使用者直接使用具體工廠要好控制一些。

使用:

public static void main(String[] args) {
    // 抽象工廠
    // IOrderFactory orderFactory = OrderFactoryProducer.getFactory("alipay");
    IOrderFactory orderFactory = OrderFactoryProducer.getFactory("wechat");
    orderFactory.getPay().order();
    orderFactory.getRefund().refund();
}
複製代碼

若是文章對您有所幫助, 請不吝點擊關注一下個人微信公衆號:FSA全棧行動, 這將是對我最大的激勵. 公衆號不只有Android技術, 還有iOS, Python等文章, 可能有你想要了解的技能知識點哦~

相關文章
相關標籤/搜索