摘要:工廠方法模式工廠方法模式是為了克服簡單工廠模式的缺點。抽象工廠模式抽象工廠模式主要在于應對新系列的需求變化。此時架構便可以升級為工廠方法模式。
在面向對象編程中創建一個對象通常通過new關鍵字來創建,但是往往在一些業務場景下,個別對象是一個比較復雜的bean。此時“創建對象”不光是new了,還需要一些額外的操作,比如填充數據,附屬對象的準備等等。如果我們想要得到這樣的一個對象,直接簡單粗暴的在需要的時候,創建、準備數據。。。做這些操作的話,那我么你的代碼將臃腫不堪,到處充斥著業務邏輯,業務需求變化時,就GG了。我們身為高貴的軟件工程師,必須保持著代碼潔癖,如何提升代碼質量呢?那就運用到今天的主角:工廠模式。
介紹工廠模式是代替new來創建對象的一種設計模式,作用是降低代碼耦合度,提升程序的易擴展性。
分類簡單工廠模式
工廠方法模式
抽象工廠模式
三種模式都是工廠模式,他們都具有工廠模式的優點,抽象程度從上到下越來越高,分別都有不同的適用場景,接下來逐一介紹。
一、簡單工廠模式簡單工廠的角色分為3個
工廠
抽象產品
具體產品
舉例:
比如我正在“吃雞”,跳傘剛落地,急需一把槍防身.
有如下類
public abstract class Gun { private String name; public Gun(String name) { this.name = name; } public void shoot(){ System.out.println(name); } } public class M416 extends Gun { public M416() { super("m416"); } } public class Ak47 extends Gun { public Ak47() { super("ak47"); } }
沒有使用工廠模式時代碼是這樣的
Gun gun = new Ak47(); 或 Gun gun = new M416();
使用了工廠模式時
public class SimpleFactory { public static Gun getGun(GunType gunType){ switch (gunType){ case AK47: return new Ak47(); case M416: return new M416(); default: return null; } } public enum GunType{ AK47,M416; } }
客戶端調用:
public class SimpleFactoryClient { public static void main(String[] args) { //得到ak47 Gun gun = SimpleFactory.getGun(SimpleFactory.GunType.AK47); //得到m416 gun = SimpleFactory.getGun(SimpleFactory.GunType.M416); } }
這樣代碼就清晰多了,這就好比沒用工廠模式時自己要冒險去找槍,需要知道業務的細節。使用了工廠模式,只需要大喊一聲我要m4,就有快遞員把槍送到你面前,而不需要知道獲得槍的過程。
這就是簡單工程模式,簡單工程模式確實將代碼解耦了,但是如果我們想要awm呢?需要增加一種枚舉,然后多加一個case語句,這是不符合設計模式的開閉原則(對擴展開放,對修改關閉)。接下來我們介紹下一種,工廠方法模式。
二、工廠方法模式工廠方法的角色分為4個
抽象工廠
具體工廠
抽象產品
具體產品
舉例:
之前簡單工廠中使用了switch case來判斷到底要返回哪個實例,此時我們可以將switch case給代替。
我們定義一個抽象的槍工廠
public interface GunFactory { Gun getGun(); }
然后分別定義具體的ak47工廠和m416工廠
public class Ak47Factory implements GunFactory { @Override public Gun getGun() { return new Ak47(); } } public class M416Factory implements GunFactory { @Override public Gun getGun() { return new M416(); } }
客戶端調用:
public class FactoryClient { public static void main(String[] args) { //獲取ak47 GunFactory gunFactory = new Ak47Factory(); Gun gun = gunFactory.getGun(); //獲取m416 gunFactory = new M416Factory(); gun = gunFactory.getGun(); } }
當我們需要獲得awm時,則只需要新增一個Awm類和一個AwmFactory讓其實現GunFactory即可,這樣避免了寫switch case,符合了開閉原則。 此時有的小伙伴可能會問,最初不適用工廠方法時是用new Ak47()來獲得槍,現在使用new Ak47Factory()不是和之前一樣嗎?說明下,這是我假設的ak47可能僅僅只是需要new以下,但在我們實際的場景中,有些bean的創建是及其復雜,他可能是其他開發人員負責的邏輯,你去對接時根本不需要了解其中的細節,只需要獲得僅此而已。工廠模式就是封裝了構建產品的細節,客戶端根據想要的產品,選擇對應的工廠就可獲得相應的產品。
我們現在得到了槍,但是還沒有子彈和配件,此時我們想要直接得到一把滿配的槍。
但是子彈的類型有多種,配件的類型也有多種,此時我們又想到了為子彈和配件創建工廠,但是我們獲得一把槍滿配的槍并不需要知道怎么獲得子彈和配件,所以我們的槍工廠就要直接包含子彈工廠和配件工廠,因此我們的抽象工廠模式呼之欲出。
抽象工廠的角色分為4個
抽象工廠
具體工廠
抽象產品(多個相同主題)
具體產品
舉例:
首先我們創建子彈的類
public abstract class Bullet { protected String name; public Bullet(String name) { this.name = name; } public String getName() { return name; } public Bullet setName(String name) { this.name = name; return this; } } public class Ak47Bullet extends Bullet { public Ak47Bullet() { super("ak的子彈"); } } public class M416Bullet extends Bullet { public M416Bullet() { super("m416的子彈"); } }
接著是子彈工廠
public interface BulletFactory { Bullet getBullet(); } public class Ak47BulletFactory implements BulletFactory { @Override public Bullet getBullet() { return new Ak47Bullet(); } } public class M416BulletFactory implements BulletFactory { @Override public Bullet getBullet() { return new M416Bullet(); } }
配件的代碼與其相同只不過是名字換一個,此時是不是發現我們的子彈工廠和我們之前實現的槍工廠其實是一模一樣的。我們都使用了工廠方法模式,但是我們最終想要獲得是完整的滿配的槍,即槍中包含了子彈和配件。所以抽象工廠模式就將一系列具有相同主題的工廠封裝在一起。
因此抽象工廠解決的范疇是產品族等級(完整的槍),工廠方法模式解決的范疇是產品等級(子彈、配件)。
槍工廠
public class Ak47Factory implements GunFactory { @Override public Gun getGun() { Bullet bullet = new Ak47Bullet(); return new Ak47(bullet); } } public class Ak47 extends Gun { public Ak47(Bullet bullet) { super("ak47"); this.setBullet(bullet); } } public abstract class Gun { private String name; private Bullet bullet; public Gun(String name) { this.name = name; } public void shoot(){ System.out.println(name + "正在使用" + bullet.getName() + "射擊"); } public Bullet getBullet() { return bullet; } public Gun setBullet(Bullet bullet) { this.bullet = bullet; return this; } }
客戶端調用
public class FactoryClient { public static void main(String[] args) { //獲取ak47 GunFactory gunFactory = new Ak47Factory(); Gun gun = gunFactory.getGun(); System.out.println(gun.getBullet());//ak的子彈 //獲取m416 gunFactory = new M416Factory(); gun = gunFactory.getGun(); System.out.println(gun.getBullet());//m416的子彈 } }總結
三種工廠方法都有各自的優缺點,也有各自的試用場景
簡單工廠方法:工廠類含有必要的判斷邏輯,可以決定在什么時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅"消費"產品。耦合度低。明確區分了各自的職責和權力,有利于整個軟件體系結構的優化。
工廠方法模式:工廠方法模式是為了克服簡單工廠模式的缺點。簡單工廠模式的工廠類隨著產品類的增加需要增加很多方法(或代碼),而工廠方法模式每個具體工廠類只完成單一任務,代碼簡潔。工廠方法模式完全滿足OCP,即它有非常良好的擴展性。
抽象工廠模式:抽象工廠模式主要在于應對“新系列”的需求變化。分離了具體的類,一個抽象工廠創建了一個完整的產品系列,所以整個產品系列會立刻改變。它有利于產品的一致性。是對多個構成產品的“零件”工廠的封裝,使一個切換產品主題變得極為容易。
其實在我們日常做需求時,代碼的架構可能是一步一步演化的,最開始接到需求可能就是連三種產品,這是我們可能就設計成簡單工廠模式。之后產品增加多了,而且其他開發人員可能也要處理這邊的邏輯,則原先的switch case很有可能就會成為bug的伏筆。此時架構便可以升級為工廠方法模式。再后來原來的產品變得龐大且復雜,需要將產品設計成多個零件構成,此時架構又可以升級成抽象工廠模式,將耦合度進一步降低,之后其他的開發者想要新增產品,一看結構清晰明了,便可以高質量的完成工作,早早下班回家。
設計模式幫助我們提升代碼質量,每種設計模式都有其適合的場景,切勿過度設計,讓技術推動業務,不定時重構代碼,不斷構造更好的自己。
歡迎各路大神不吝賜教。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68166.html
摘要:基于工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。工廠方法模式之所以又被稱為多態工廠模式,是因為所有的具體工廠類都具有同一抽象父類。工廠方法模式總結工廠方法模式是簡單工廠模式的進一步抽象和推廣。 JavaScript工廠模式 首先需要說一下工廠模式。工廠模式根據抽象程度的不同分為三種 簡單工廠模式 工廠方法模式 抽象工廠模式 1.簡單工廠模式 簡單工廠模式:又稱為靜態工廠方法...
摘要:二簡單工廠模式組成工廠類工廠模式的核心,通過調用它來實現其他類的功能。三工廠方法模式利用工廠方法模式可以有效解決簡單工廠模式破壞開閉原則的問題。 一、概念 1、工廠模式分為三類:(1)簡單工廠模式:一個工廠創建所有產品(2)工廠方法模式:一個工廠方法創建一個產品(3)抽象工廠模式:一個工廠方法創建一類產品 2、創建型模式這種模式是指將實例的創建和使用分離開來,隱藏類實例的創建細節,外界...
摘要:簡單工廠,工廠模式和抽象工廠。不要認為簡單工廠是用就覺得一無是處,也不要覺得抽象工廠比較高大上就到處套。 工廠模式,實際上也會根據業務情景不同會有不同的實現方式。一般分為3種。簡單工廠,工廠模式和抽象工廠。顧名思義,這三種從簡單到抽象,名稱越來越高大上,實現方式肯定是越來越復雜 結論1:三種工廠的實現越來越復雜 簡單工廠 public class Factory { // 定義...
摘要:我認為按書上的順序比較好理解因為簡單靜態工廠模式是在工廠方法模式上縮減,抽象工廠模式是在工廠方法模式上再增強。所以我就先講工廠方法模式了。抽象工廠模式抽象工廠模式就比較復雜了,我們一般的應用都寫不到。 前言 只有光頭才能變強 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡單啦 單例模式你會幾種寫法? 昨天寫了單例模式了,今天是時候寫工廠模式啦~ 工廠模式我個人認為其實比...
閱讀 1985·2021-09-26 10:19
閱讀 3257·2021-09-24 10:25
閱讀 1641·2019-12-27 11:39
閱讀 1929·2019-08-30 15:43
閱讀 670·2019-08-29 16:08
閱讀 3509·2019-08-29 16:07
閱讀 909·2019-08-26 11:30
閱讀 1273·2019-08-26 10:41