<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在Java應用程式中物件無處不在,這些物件都需要進行建立,如果建立的時候直接new物件,那麼如果我們要更換物件,所有new物件的地方都需要進行更改。違背了軟體設計原則中的開閉原則。如果我們使用工廠生產物件,只需要在工廠中關注物件的改變即可,達到了與物件解耦的目的,工廠模式最大的特點就是解耦合
補充:
開閉原則: 對擴充套件開放,對修改關閉。在程式需要進行擴充套件的時候,不能去修改原有的程式碼,實現一個熱插拔的效果。是為了使程式的擴充套件性好,易於維護和升級。
以點咖啡為例:
咖啡抽象類
public abstract class Coffee { /** * 獲取咖啡型別 * @return */ public abstract String getName(); /** *加糖 */ public void addSugar(){ System.out.println("加糖"); } /** *加奶 */ public void addMilk(){ System.out.println("加奶"); } }
美式咖啡類
public class AmericanCoffee extends Coffee{ @Override public String getName(){ return "美式咖啡"; } }
拿鐵咖啡類
public class LatteCoffee extends Coffee { @Override public String getName(){ return "拿鐵咖啡"; } }
咖啡工廠類
public class CoffeeFactory { public Coffee createCoffee(String type){ Coffee coffee = null; if("american".equals(type)){ coffee = new AmericanCoffee(); }else if("latten".equals(type)){ coffee = new LatteCoffee(); }else{ throw new RuntimeException("沒有此型別的咖啡"); } return coffee; } }
咖啡店類
public class CoffeeStore { public Coffee orderCoffee(String type){ CoffeeFactory factory = new CoffeeFactory(); //呼叫生產咖啡的方法 Coffee coffee = factory.createCoffee(type); coffee.addMilk(); coffee.addSugar(); return coffee; } }
測試類
public class Test { public static void main(String[] args) { CoffeeStore coffeeStore = new CoffeeStore(); Coffee coffee = coffeeStore.orderCoffee("latten"); System.out.println(coffee.getName()); } }
類圖
咖啡工廠負責生產咖啡(具體工廠),咖啡店通過咖啡工廠選取咖啡
其實簡單工廠是大家在實際寫程式碼的時候經常用到的,雖然簡單工廠實現了咖啡店與咖啡的耦合,但是可以明顯看到咖啡與咖啡工廠又耦合起來了,後期如果增加咖啡的新品種,我們需要修改咖啡工廠的程式碼,這又違背了「開閉原則」。
注意:
簡單工廠和不使用工廠是有很大區別的,如果咖啡店有多個,不使用工廠如果遇到新增咖啡需要修改所有咖啡店,但是使用工廠只需要修改咖啡工廠,類似於將所有咖啡店抽取出一個抽象的咖啡店。
優點:
封裝了建立物件的過程,可以通過引數直接獲取物件,把物件的建立和業務邏輯層分開,這樣可以避免之後修改客戶程式碼,如果需要實現新產品直接修改工廠類,更容易擴充套件。
缺點:
增加新產品時還需要修改工廠類的程式碼,違背了「開閉原則」。
靜態工廠,將工廠類中建立物件的功能定義為靜態的,這樣不需要再建立工廠類,直接通過類名呼叫靜態方法,類似於工具類
public class CoffeeFactory { //靜態方法 public static Coffee createCoffee(String type){ Coffee coffee = null; if("american".equals(type)){ coffee = new AmericanCoffee(); }else if("latten".equals(type)){ coffee = new LatteCoffee(); }else{ throw new RuntimeException("沒有此型別的咖啡"); } return coffee; } }
對工廠進行抽象,每一種產品對應一個具體工廠,新增產品只需要再新增對應的具體工廠,符合」開閉原則「
抽象咖啡類和具體咖啡類不變
咖啡工廠(抽象工廠)
public interface CoffeeFactory { /** * 建立咖啡 * @return */ Coffee createCoffee(); }
美式咖啡工廠(具體工廠)
public class AmericanCoffeeFactory implements CoffeeFactory{ //美式咖啡工廠物件,專門生產美式咖啡 @Override public Coffee createCoffee() { return new AmericanCoffee(); } }
拿鐵咖啡工廠(具體工廠)
public class LatteCoffeeFactory implements CoffeeFactory{ //拿鐵咖啡工廠物件,專門生產拿鐵咖啡 @Override public Coffee createCoffee() { return new LatteCoffee(); } }
咖啡店
public class CoffeeStore { private CoffeeFactory factory; public void setFactory(CoffeeFactory factory) { this.factory = factory; } /** * 點咖啡 */ public Coffee orderCoffee() { Coffee coffee = factory.createCoffee(); coffee.addSugar(); coffee.addMilk(); return coffee; } }
測試類
public class Test { public static void main(String[] args) { //建立咖啡店物件 CoffeeStore coffeeStore = new CoffeeStore(); //建立工廠物件 CoffeeFactory factory = new AmericanCoffeeFactory(); coffeeStore.setFactory(factory); //點咖啡 Coffee coffee = coffeeStore.orderCoffee(); System.out.println(coffee.getName()); } }
類圖
我們只需要知道所點咖啡具體對應的工廠物件,通過咖啡店呼叫對應的工廠,由工廠建立咖啡物件實現點咖啡的過程
優點:
缺點:
每增加一個產品就要增加一個對應的具體工廠類,增加的系統的複雜性。如果具體產品種類過多,那麼大量的工廠類不僅難以管理,而且也會造成程式中建立的物件過多,嚴重影響記憶體效能
咖啡抽象類
public abstract class Coffee { /** * 獲取咖啡型別 * @return */ public abstract String getName(); /** *加糖 */ public void addSugar(){ System.out.println("加糖"); } /** *加奶 */ public void addMilk(){ System.out.println("加奶"); } }
美式咖啡類
public class AmericanCoffee extends Coffee{ @Override public String getName(){ return "美式咖啡"; } }
拿鐵咖啡類
public class LatteCoffee extends Coffee { @Override public String getName(){ return "拿鐵咖啡"; } }
甜品抽象類
public abstract class Dessert { //甜品抽象類 public abstract void show(); }
抹茶慕斯類
public class MatchaMousse extends Dessert{ //抹茶慕斯類 @Override public void show() { System.out.println("抹茶慕斯"); } }
提拉米蘇類
public class Tiramisu extends Dessert{ //提拉米蘇類 @Override public void show() { System.out.println("提拉米蘇"); } }
甜品工廠
public interface DessertFactory { /** * 生產咖啡 * @return */ Coffee createCoffee(); /** * 生產甜品 * @return */ Dessert createDessert(); }
美式風味甜品工廠類
public class AmericanDessertFactory implements DessertFactory{ /** *美式風味甜品工廠 * 可以生產美式咖啡和抹茶慕斯 */ @Override public Coffee createCoffee() { return new AmericanCoffee(); } @Override public Dessert createDessert() { return new MatchaMousse(); } }
義大利風味甜品工廠類
public class ItalyDessertFactory implements DessertFactory { /** *義大利風味甜品工廠 * 可以生產拿鐵咖啡和提拉米蘇 */ @Override public Coffee createCoffee() { return new LatteCoffee(); } @Override public Dessert createDessert() { return new Tiramisu(); } }
測試類
public class Test { public static void main(String[] args) { //ItalyDessertFactory factory = new ItalyDessertFactory(); AmericanDessertFactory factory = new AmericanDessertFactory(); Coffee coffee = factory.createCoffee() Dessert dessert = factory.createDessert(); System.out.println(coffee.getName()); dessert.show(); } }
類圖
由類圖可見,抽象工廠不再是一個具體工廠對應一個產品,而是一個具體工廠對應一個產品族。如果需要增加一個產品族只需加對應的工廠類,符合」開閉原則「
優點:
在工廠方法的基礎上減少了部分物件的建立,適合於每次只使用同一產品族的物件這類應用場景
缺點:
當產品族中需要增加一個產品時,所有工廠都要修改
組態檔+簡單工廠
通過工廠模式+組態檔的方式解除工廠物件和產品物件的耦合。在工廠類中載入組態檔的全類名,通過反射建立物件並儲存在容器中,如果需要直接從容器中獲取(Spring IOC原理)
1.定義組態檔
american = com.xue.config_factory.AmericanCoffee latten = com.xue.config_factory.LatteCoffee
2.改進工廠類
public class CoffeeFactory { /** * 載入組態檔,獲取組態檔中設定的全類名,並建立該類的物件進行儲存 */ //1.定義容器物件儲存咖啡物件 private static HashMap<String, Coffee> map = new HashMap<>(); //2.載入組態檔 static { //建立 Properties物件 Properties properties = new Properties(); //呼叫properties物件中的load方法進行組態檔的載入 InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties"); try { properties.load(is); //從properties中獲取全類名 Set<Object> keys = properties.keySet(); for (Object key : keys) { String className = properties.getProperty((String) key); //通過反射建立物件 Class class1 = Class.forName(className); Coffee coffee = (Coffee) class1.newInstance(); //將名稱和物件儲存在容器中 map.put((String) key,coffee); } } catch (Exception e) { e.printStackTrace(); } } //根據名稱獲取物件 public static Coffee createCoffee(String name) { return map.get(name); } }
靜態成員變數用來儲存建立的物件(鍵儲存的是名稱,值儲存的是對應的物件),而讀取組態檔和建立物件寫在靜態程式碼塊中只需要執行一次
測試類
public class Test { public static void main(String[] args) { Coffee coffee = CoffeeFactory.createCoffee("american"); System.out.println(coffee.getName()); System.out.println("------------"); Coffee latten = CoffeeFactory.createCoffee("latten"); System.out.println(latten.getName()); } }
成功!!!
以上就是Java設計模式——工廠模式的介紹及四種實現方式 往期連結:單例模式
到此這篇關於Java超詳細講解設計模式之一的工廠模式的文章就介紹到這了,更多相關Java 工廠模式內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45