你還在處處 new 對象嗎?java
單身狗:我沒對象,new 怎麼了?git
new 對象自己是沒問題的,但也不能所有 new 關鍵字走天下,其實有更好的方式,合適的時候能夠試試工廠模式,代碼會更優雅。程序員
顧名思義,工廠模式中的 "工廠" 指的是建立對象的工廠,它提供了一種建立對象的最佳方式,也就是工廠模式。github
工廠模式的好處是這些對象不須要暴露自身的建立過程,統一由工廠模式進行建立和提供,隱藏了建立細節,避免了錯誤的建立對象的形式,也減小了重複建立冗餘代碼。面試
通常狀況下,工廠模式能夠細分爲三類:spring
不過在設計模式權威書籍《設計模式:可複用面向對象軟件的基礎》一書中,簡單工廠模式只是工廠方法模式的一個特例而已。設計模式
因此,從權威的角度說,工廠模式只分爲: 工廠模式 和 抽象工廠模式 兩大類。intellij-idea
但無論白貓黑貓,能抓老鼠的就是好貓,設計模式亦是如此,無論怎麼分類,這些模式都是程序員們歷年過往經驗的濃縮,都是值得學習和借鑑的。ide
因此,本文棧長從細分的角度帶你們來實戰下這三個工廠設計模式。工具
好比 XX 公司是作支付的,公司有幾大類的客戶:電商商戶、銀行客戶、代理商……
建立這些客戶的時候咱們能夠用簡單工廠模式來實現看看。
新建客戶基類:
能夠把全部客戶公共的信息放到一個客戶基類中,好比:客戶名、客戶類型等,全部的客戶繼承這個抽象基類。
/** * 客戶 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @NoArgsConstructor @AllArgsConstructor public abstract class Customer { /** * 客戶名稱 */ private String name; /** * 客戶類型 */ private String type; }
新建電商商戶類:
/** * 商戶 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @ToString(callSuper = true) public class Merchant extends Customer { /** * 合同類型 */ private int contractType; /** * 結算週期(天) */ private int settmentDays; public Merchant(String name, String type) { super(name, type); } }
新建銀行客戶類:
/** * 銀行客戶 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @ToString(callSuper = true) public class BankPartner extends Customer { /** * 銀行編碼 */ private String code; /** * 銀行地址 */ private String address; public BankPartner(String name, String type) { super(name, type); } }
新建代理商類:
/** * 代理商 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @ToString(callSuper = true) public class Agent extends Customer { /** * 代理週期 */ private int period; /** * 代理產品 */ private int[] products; public Agent(String name, String type) { super(name, type); } }
新增簡單工廠類:
新建一個簡單工廠,提供一個公共靜態方法,根據不一樣的客戶類型建立不一樣的客戶。
/** * 客戶簡單工廠 * @author: 棧長 * @from: 公衆號Java技術棧 */ public class CustomerFactory { private static Merchant createMerchant(String type, String name) { return new Merchant(type, name); } private static BankPartner createBankPartner(String type, String name) { return new BankPartner(type, name); } private static Agent createAgent(String type, String name) { return new Agent(type, name); } public static Customer create(String type, String name) { if ("M".equals(type)) { return createMerchant(type, name); } else if ("B".equals(type)) { return createBankPartner(type, name); } else if ("A".equals(type)) { return createAgent(type, name); } return null; } }
新建測試類:
/** * @author: 棧長 * @from: 公衆號Java技術棧 */ public class Test { public static void main(String[] args) { Customer merchant = CustomerFactory.create("M", "Java技術棧商戶"); System.out.println(merchant); Customer bankPartner = CustomerFactory.create("B", "Java技術棧銀行客戶"); System.out.println(bankPartner); Customer agent = CustomerFactory.create("A", "Java技術棧代理商"); System.out.println(agent); } }
輸出結果:
本節教程全部實戰源碼已上傳到這個倉庫:
能夠看出簡單工廠的使用很簡單,就是耦合性過高了。
第一,對象和基類之間是基於繼承的。
第二,工廠類耦合了不一樣對象的建立,若是對象類型不是固定或者常常變更的,就要頻繁修改工廠類,好比我如今要再加一種客戶,就必需要改動工廠類,不符開閉原則。
因此,簡單工廠只適用於固定類型對象的建立。
工廠方法就是爲某類產品提供一個工廠接口,而後爲每一個產品提供一個工廠實現類。
廢話少說,咱們將簡單工廠的示例用工廠方法再改造一下。
新建工廠方法接口:
/** * 工廠方法客戶接口 * @author: 棧長 * @from: 公衆號Java技術棧 */ public interface CustomerFactory { Customer create(String type, String name); }
新建商戶工廠實現類:
/** * 商戶工廠 * @author: 棧長 * @from: 公衆號Java技術棧 */ public class MerchantFactory implements CustomerFactory { @Override public Customer create(String type, String name) { return new Merchant(type, name); } }
新建銀行客戶工廠實現類:
/** * 銀行客戶工廠 * @author: 棧長 * @from: 公衆號Java技術棧 */ public class BankPartnerFactory implements CustomerFactory { @Override public Customer create(String type, String name) { return new BankPartner(type, name); } }
新建代理商工廠實現類:
/** * 代理商工廠 * @author: 棧長 * @from: 公衆號Java技術棧 */ public class AgentFactory implements CustomerFactory { @Override public Customer create(String type, String name) { return new Agent(type, name); } }
新建測試類:
/** * @author: 棧長 * @from: 公衆號Java技術棧 */ public class Test { public static void main(String[] args) { System.out.println("------工廠模式-工廠方法------"); CustomerFactory merchantFactory = new MerchantFactory(); Customer merchant = merchantFactory.create("M", "Java技術棧商戶"); System.out.println(merchant); CustomerFactory bankPartnerFactory = new BankPartnerFactory(); Customer bankPartner = bankPartnerFactory.create("B", "Java技術棧銀行客戶"); System.out.println(bankPartner); CustomerFactory agentFactory = new AgentFactory(); Customer agent = agentFactory.create("A", "Java技術棧代理商"); System.out.println(agent); } }
輸出結果:
本節教程全部實戰源碼已上傳到這個倉庫:
能夠看出,工廠方法也是挺簡單易用的,耦合性問題也解決了,每增長一個產品就新增一個產品工廠實現類就好了,擴展性很是好。
但也有一個問題,若是產品很是多,那勢必會形成工廠實現類氾濫,另一種可怕的場景就是,若是涉及到工廠接口變動,工廠實現類的維護簡直就是一種惡夢。
工廠方法中一個工廠只能建立一個對象,若是如今每次建立客戶的時候都須要同時建立一份客戶擴展資料,那就能夠考慮使用抽象工廠。
新建客戶擴展基類:
能夠把全部客戶公共的擴展信息放到一個客戶擴展基類中,好比:客戶曾用名、客戶擴展說明等,全部的客戶繼承這個擴展抽象基類。
/** * 客戶擴展 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @NoArgsConstructor public abstract class CustomerExt { /** * 客戶曾用名 */ private String formerName; /** * 客戶擴展說明 */ private String note; }
新建商戶擴展類:
/** * 商戶 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @ToString(callSuper = true) public class MerchantExt extends CustomerExt { /** * 介紹人 */ private int introduceName; /** * 介紹人電話 */ private String introduceTel; }
新建銀行客戶擴展類:
/** * 銀行客戶擴展 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @ToString(callSuper = true) public class BankPartnerExt extends CustomerExt { /** * 分行個數 */ private int branchCount; /** * ATM個數 */ private int atmCount; }
新建代理商擴展類:
/** * 商戶 * @author: 棧長 * @from: 公衆號Java技術棧 */ @Data @ToString(callSuper = true) public class AgentExt extends CustomerExt { /** * 來源 */ private String source; /** * 資質 */ private String certification; }
新建抽象工廠接口:
/** * 抽象工廠客戶接口 * @author: 棧長 * @from: 公衆號Java技術棧 */ public interface CustomerFactory { Customer createCustomer(String type, String name); CustomerExt createCustomerExt(); }
新建商戶工廠實現類:
/** * 商戶工廠 * @author: 棧長 * @from: 公衆號Java技術棧 */ public class MerchantFactory implements CustomerFactory { @Override public Customer createCustomer(String type, String name) { return new Merchant(type, name); } @Override public CustomerExt createCustomerExt() { return new MerchantExt(); } }
新建銀行客戶工廠實現類:
/** * 銀行客戶工廠 * @author: 棧長 * @from: 公衆號Java技術棧 */ public class BankPartnerFactory implements CustomerFactory { @Override public Customer createCustomer(String type, String name) { return new BankPartner(type, name); } @Override public CustomerExt createCustomerExt() { return new BankPartnerExt(); } }
新建代理商工廠實現類:
/** * 代理商工廠 * @author: 棧長 * @from: 公衆號Java技術棧 */ public class AgentFactory implements CustomerFactory { @Override public Customer createCustomer(String type, String name) { return new Agent(type, name); } @Override public CustomerExt createCustomerExt() { return new AgentExt(); } }
新建測試類:
/** * @author: 棧長 * @from: 公衆號Java技術棧 */ public class Test { public static void main(String[] args) { System.out.println("------工廠模式-抽象工廠------"); CustomerFactory merchantFactory = new MerchantFactory(); Customer merchant = merchantFactory.createCustomer("M", "Java技術棧商戶"); CustomerExt merchantExt = merchantFactory.createCustomerExt(); System.out.println(merchant); System.out.println(merchantExt); CustomerFactory bankPartnerFactory = new BankPartnerFactory(); Customer bankPartner = bankPartnerFactory.createCustomer("B", "Java技術棧銀行客戶"); CustomerExt bankPartnerExt = bankPartnerFactory.createCustomerExt(); System.out.println(bankPartner); System.out.println(bankPartnerExt); CustomerFactory agentFactory = new AgentFactory(); Customer agent = agentFactory.createCustomer("A", "Java技術棧代理商"); CustomerExt agentExt = agentFactory.createCustomerExt(); System.out.println(agent); System.out.println(agentExt); } }
輸出結果:
能夠看出,抽象工廠和工廠方法十分相似,只不過抽象工廠裏面只生產一個對象,而抽象工廠能夠生產多個對象。
抽象工廠缺點也很明顯,第一就是和工廠方法同樣工廠類很是多,第二就是擴展很是麻煩,好比我如今要爲每一個客戶類型再加一份客戶特殊資料,那全部涉及到抽象工廠的工廠類都要改,是否是要瘋了。。
若是有多個屬於同一種類型的類,能夠考慮使用工廠模式,統一提供生成入口,能從必定程度上解耦,擴展方便,也不用再處處 new 對象了。
但話又說回來,從示例能夠看出,若是使用或者設計不當也會帶來維護上的工做量。
本節教程全部實戰源碼已上傳到這個倉庫:
好了,今天的分享就到這裏了,後面棧長我會更新其餘設計模式的實戰文章,公衆號Java技術棧第一時間推送。Java技術棧《設計模式》系列文章陸續更新中,請你們持續關注哦!
最後,以爲個人文章對你用收穫的話,動動小手,給個在看、轉發,原創不易,棧長鬚要你的鼓勵。
版權申明:本文系公衆號 "Java技術棧" 原創,原創實屬不易,轉載、引用本文內容請註明出處,禁止抄襲、洗稿,請自重,尊重你們的勞動成果和知識產權,抄襲必究。
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2021最新版)
2.終於靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!
3.阿里 Mock 工具正式開源,幹掉市面上全部 Mock 工具!
4.Spring Cloud 2020.0.0 正式發佈,全新顛覆性版本!
以爲不錯,別忘了隨手點贊+轉發哦!