欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設計模式之簡單工廠 工廠方法 抽象工廠深度總結

 更新時間:2021年09月24日 15:28:34   作者:沒頭腦遇到不高興  
設計模式(Design Pattern)是前輩們對代碼開發(fā)經驗的總結,是解決特定問題的一系列套路。它不是語法規(guī)定,而是一套用來提高代碼可復用性、可維護性、可讀性、穩(wěn)健性以及安全性的解決方案

工廠模式介紹

工廠模式也是非常常見的設計模式之一,其屬于創(chuàng)建型模式。工廠模式分類:簡單工廠(Simple Factory)、工廠方法(Factory Method)、抽象工廠(Abstract Factory),嚴格來講,簡單工廠不屬于工廠設計模式。

好處

  • 解耦:工廠模式主要是為了對象的創(chuàng)建和使用的分離
  • 降低代碼重復:如果對象創(chuàng)建很復雜,則每次創(chuàng)建都需要重復很多代碼,通過工廠包裝起來可以減少重復代碼
  • 方便維護:如果創(chuàng)建對象的邏輯有修改,則只需要修改工廠內代碼,而不用修改每個創(chuàng)建對象的代碼。

常見的應用

  • Spring中的BeanFactory.getBean(beanName)
  • 日志當中的LoggerFactory.getLogger(name)
  • Java加密時 KeyGenerator keygen=KeyGenerator.getInstance("AES");
  • RabbitMQ的Java客戶端創(chuàng)建連接 :
//創(chuàng)建連接工廠
ConnectionFactory factory = new ConnectionFactory("192.168.74.4");
// 通過連接工廠獲取連接
Connection connection = factory.newConnection();

簡單工廠(Simple Factory)

簡單工廠并不在23種設計模式之中,屬于特殊的工廠模式,應用的相對來說少一點??蛻舳藢嵗瘜ο蟮臅r候不用通過new Audi()的方式,而是可以通過往統(tǒng)一工廠傳入相應的條件返回對應的實例對象(主要通過if-else或者switch-case進行判斷,違背了開閉原則),屏蔽了實例化對象的具體邏輯細節(jié)。

適用場景

  1. 需要創(chuàng)建的對象較少。
  2. 客戶端不關心對象的創(chuàng)建過程。

角色分配:

  • 工廠(Factory)角色:簡單工廠模式的核心,它負責實現創(chuàng)建所有實例的內部邏輯。工廠類可以被外界直接調用,創(chuàng)建所需的產品對象。
  • 抽象產品(Product)角色 :簡單工廠模式所創(chuàng)建的所有對象的父類,它負責描述所有實例所共有的公共接口。
  • 具體產品(Concrete Product)角色:簡單工廠模式的創(chuàng)建目標,所有創(chuàng)建的對象都是充當這個角色的某個具體類的實例。

其UML類圖如下所示:

應用案例:

  • Java加密時 KeyGenerator keygen=KeyGenerator.getInstance("AES");
  • DateFormat類中的public final static DateFormat getDateInstance(int style)

優(yōu)缺點:

  • 優(yōu)點:實現簡單,隱藏了創(chuàng)建對象的細節(jié),創(chuàng)建對象的邏輯修改時,客戶端不用進行修改。
  • 缺點:違背了開閉原則,每次新增刪除子類的時候都要修改工廠的邏輯,而且創(chuàng)建對象的邏輯都包含在工廠內,后面子類太多的話這塊代碼會非常多,難以維護。

簡單工廠實現:

我們創(chuàng)建一個Car接口,里面包含一個getName方法用以返回具體的品牌名稱,接口有兩個實現類Audi和Bmw,分別返回了品牌名稱 "Audi" 和 "Bmw"。

package com.wkp.designpattern.factory;
//汽車接口
public interface Car {
 
	//返回汽車的品牌
	public String getName();
}
package com.wkp.designpattern.factory;
 
public class Audi implements Car {
 
	public String getName() {
		return "Audi";
	}
}
package com.wkp.designpattern.factory;
 
public class Bmw implements Car {
 
	public String getName() {
		return "Bmw";
	}
}

下面是簡單工廠的核心,用于創(chuàng)建對象

package com.wkp.designpattern.simple.factory;
 
import com.wkp.designpattern.factory.Audi;
import com.wkp.designpattern.factory.Bmw;
import com.wkp.designpattern.factory.Car;
 
public class SimpleFactory {
 
	public Car getCar(String name){
		if("Audi".equals(name)){
			return new Audi();
		}else if("Bmw".equals(name)){
			return new Bmw();
		}else{
			System.out.println("沒法生產這個車");
			return null;
		}
	}
}

測試代碼如下:

package com.wkp.designpattern.simple.factory;
import com.wkp.designpattern.factory.Car;
 
public class SimpleFactoryTest {
 
	public static void main(String[] args) {
		SimpleFactory factory = new SimpleFactory();
		
		Car car1 = factory.getCar("Audi");
		System.out.println(car1.getName());
		Car car2 = factory.getCar("Bmw");
		System.out.println(car2.getName());
	}
}

輸出結果如下:

Audi
Bmw

這里每增加一個新的子類,getCar方法就要添加if判斷,刪除了子類這里也要修改,顯然違反了開閉原則,而且創(chuàng)建對象的邏輯全部都在這個方法中,隨著創(chuàng)建對象的增加,這里的邏輯會非常多。當然我們可以通過反射的方式對上面的工廠進行改進如下:

//利用反射改進的簡單工廠,添加的時候不用修改getCar方法
public class ReflectSimpleFactory {
 
	//參數className為完整類名
	public Car getCar(String className){
		Car obj=null;
		try {
			obj=(Car) Class.forName(className).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return obj;
	}
}
public class ReflectSimpleFactoryTest {
 
	public static void main(String[] args) {
		ReflectSimpleFactory factory = new ReflectSimpleFactory();
		Car car1 = factory.getCar("com.wkp.designpattern.factory.Audi");
		System.out.println(car1.getName());
		Car car2 = factory.getCar("com.wkp.designpattern.factory.Bmw");
		System.out.println(car2.getName());
	}
}

輸出結果不變,也符合了開閉原則,但是要傳入完整類名也不方便,可以通過xml或者配置文件的方式進行改進。

工廠方法(Factory Method)

工廠方法的應用是最多的,工廠方法中不再提供統(tǒng)一的工廠創(chuàng)建對象,而是針對不同的對象提供不同的工廠。定義一個創(chuàng)建對象的接口,讓其子類自己決定實例化哪一個工廠類,創(chuàng)建過程延遲到子類進行。

適用場景

  • 當一個類不知道它所必須創(chuàng)建的對象的類的時候:工廠方法模式中客戶端不需要知道對象的名稱,只需要知道要創(chuàng)建的對象對應的工廠即可。
  • 當一個類希望由它的子類來指定它所創(chuàng)建的對象的時候:工廠方法模式中定義了一個Factory接口,該接口包含一個創(chuàng)建對象的抽象方法,具體的創(chuàng)建對象的邏輯由其實現類完成。
  • 當類將創(chuàng)建對象的職責委托給多個幫助子類中的某一個,并且你希望將哪一個幫助子類是代理者這一信息局部化的時候。

角色分配:

  • 抽象工廠(Abstract Factory)角色:是工廠方法模式的核心,提供了創(chuàng)建對象的接口,任何在模式中創(chuàng)建的對象的工廠類必須實現這個接口。
  • 具體工廠(Concrete Factory)角色:這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,并且受到應用程序調用以創(chuàng)建某一種產品對象。
  • 抽象產品(AbstractProduct)角色 :工廠方法模式所創(chuàng)建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
  • 具體產品(Concrete Product)角色 :這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創(chuàng)建,它們之間往往一一對應

其UML類圖如下所示:

應用案例:

  • spring-data-redis中創(chuàng)建redis連接的地方,RedisConnectionFactory接口提供了創(chuàng)建連接的方法RedisConnection getConnection(),該工廠的兩個實現類JedisConnectionFactory ,LettuceConnectionFactory分別用于創(chuàng)建jedis和lettuce連接

優(yōu)缺點:

  • 優(yōu)點:符合開閉原則,添加子類時只需要添加對應的工廠類即可,而不用修改原有的工廠類,每個對象的創(chuàng)建邏輯都在對應的工廠類中,代碼邏輯清晰,易于維護。
  • 缺點:每次增加一個產品時,都需要增加一個具體類和對象實現工廠,使得系統(tǒng)中類的個數成倍增加,在一定程度上增加了系統(tǒng)的復雜度,同時也增加了系統(tǒng)具體類的依賴。

工廠方法實現:

定義一個Factory接口,里面提供了一個getCar()方法,具體的創(chuàng)建邏輯由其實現類去完成。

public interface Factory {
 
	public Car getCar();
}

下面是Factory接口的具體實現類,用于創(chuàng)建對應的對象

public class AudiFactory implements Factory {
 
	public Car getCar() {
		return new Audi();
	}
}
public class BmwFactory implements Factory {
 
	public Car getCar() {
		return new Bmw();
	}
}

測試類如下:

public class FuncFactoryTest {
 
	public static void main(String[] args) {
		Car car1 = new AudiFactory().getCar();
		System.out.println(car1.getName());
		
		Car car2 = new BmwFactory().getCar();
		System.out.println(car2.getName());
	}
}

抽象工廠(Abstract Factory)

上面的工廠模式生產的都是一類產品,而抽象工廠模式可以生產產品族。什么是產品族呢?其實就是一組具有關聯(lián)關系的產品集合,舉幾個例子:

  • 比如生產電腦,用Intel系列、AMD系列的零件(CPU、主板。。。。。),每個系列的零件就是一個產品族。
  • 比如我們開發(fā)過程中會用到MySQL、Oracle數據庫,而不同的數據庫的操作會有不同,比如有User,Order兩個類,兩個類都有添加、修改操作,那User、Order的操作就要隨著數據庫的切換而切換,MySQL和Oracle下不同的類就組成了兩個產品族。
  • 我們用QQ空間的時候會有換皮膚的功能,而每套皮膚下的背景、按鈕、導航、菜單。。。。。。這些也構成了產品族
  • 我們上面用的生產汽車的例子,比如奧迪,寶馬不同品牌車的零部件(輪胎、發(fā)動機、軸承。。。。。。)

適用場景

  • 和工廠方法一樣客戶端不需要知道它所創(chuàng)建的對象的類。
  • 需要一組對象共同完成某種功能時,并且可能存在多組對象完成不同功能的情況。(同屬于同一個產品族的產品)
  • 系統(tǒng)結構穩(wěn)定,不會頻繁的增加對象。(因為一旦增加就需要修改原有代碼,不符合開閉原則)

角色分配

  • 抽象工廠(AbstractFactory)角色 :是工廠方法模式的核心,與應用程序無關。任何在模式中創(chuàng)建的對象的工廠類必須實現這個接口。
  • 具體工廠類(ConcreteFactory)角色 :這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,并且受到應用程序調用以創(chuàng)建某一種產品對象。
  • 抽象產品(Abstract Product)角色 :工廠方法模式所創(chuàng)建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
  • 具體產品(Concrete Product)角色 :抽象工廠模式所創(chuàng)建的任何產品對象都是某一個具體產品類的實例。在抽象工廠中創(chuàng)建的產品屬于同一產品族,這不同于工廠模式中的工廠只創(chuàng)建單一產品。

其UML類圖如下所示:

應用案例:

QQ空間換膚、更換數據庫等

優(yōu)缺點:

  • 優(yōu)點:可以創(chuàng)建系列產品,方便切換使用的產品系列。
  • 缺點:擴展產品族較為麻煩,不光要添加所有的抽象產品實現,還要添加產品族對應的工廠;另外添加產品也不簡單,要添加抽象產品,所有的產品族實現,還要對原先的工廠實現添加工廠方法以生產新產品。

抽象工廠實現

這個案例我們就以生產電腦為例,眾所周知目前電腦的CPU有兩大品牌:Intel和AMD。我們就以此為例,如果電腦選用Intel系列,就要用Intel的CPU和主板等,如果用AMD系列,就用AMD系列的零部件。

下面的兩個接口就是我們上面提到的抽象產品角色。

//CPU
public interface CPU {
 
	public String getName();
}
//主板
public interface MainBoard {
 
	public String getName();
}

下面的四個類就是我們上面提到的具體產品角色。首先是Intel系列產品

public class IntelCPU implements CPU {
 
	public String getName() {
		return "IntelCPU";
	}
 
}
public class IntelMainBoard implements MainBoard{
 
	public String getName() {
		return "IntelMainBoard";
	}
 
}

然后是AMD系列產品:

public class AMDCPU implements CPU {
 
	public String getName() {
		return "AMDCPU";
	}
 
}
public class AMDMainBoard implements MainBoard{
 
	public String getName() {
		return "AMDMainBoard";
	}
 
}

下面的Factory就是抽象工廠角色,提供了生產CPU和主板的抽象方法。

public interface Factory {
	//生產CPU
	public CPU createCPU();
	//生產主板
	public MainBoard createMainBoard();
}

然后是具體的工廠類角色,分別生產不同系列的產品。

//Intel系列產品工廠
public class IntelFactory implements Factory {
 
	public CPU createCPU() {
		return new IntelCPU();
	}
 
	public MainBoard createMainBoard() {
		return new IntelMainBoard();
	}
 
}
//AMD系列產品工廠
public class AMDFactory implements Factory {
 
	public CPU createCPU() {
		return new AMDCPU();
	}
 
	public MainBoard createMainBoard() {
		return new AMDMainBoard();
	}
 
}

測試類如下:

public class FactoryTest {
 
	public static void main(String[] args) {
		Factory intel = new IntelFactory();
		System.out.println(intel.createCPU().getName());
		System.out.println(intel.createMainBoard().getName());
		
		Factory amd = new AMDFactory();
		System.out.println(amd.createCPU().getName());
		System.out.println(amd.createMainBoard().getName());
	}
}

運行結果為:

IntelCPU
IntelMainBoard
AMDCPU
AMDMainBoard

抽象工廠終極改進(反射+配置文件+簡單工廠)

上面也說過抽象工廠的缺點是擴展產品族比較麻煩,我們對上面的抽象工廠做個改進,使其在添加產品族的時候更簡單一些。我們引入簡單工廠,但是簡單工廠擴展的時候要添加判斷條件,所以我們可以通過反射+配置文件去解決這個問題。改動后的UML圖如下所示:

改進后的代碼如下所示:Configuration類用于讀取配置文件(沒有具體去實現)

type=Intel
packageName=com.wkp.design.pattern.factory.abst
public class SimpleFactory {
 
	static class Configuration{
		public static String get(String key){
			String value="";//TODO 讀取配置文件得到value
			return value;
		}
	}
	
	//通過配置文件讀取產品族類型及包名
	private static final String type=Configuration.get("type");
	private static final String packageName=Configuration.get("packageName");
	
	//生產CPU
	public CPU createCPU() throws Exception{
		return (CPU)Class.forName(packageName+"."+type+"CPU").newInstance();
	}
	//生產主板
	public MainBoard createMainBoard() throws Exception{
		return (MainBoard)Class.forName(packageName+"."+type+"MainBoard").newInstance();
	}
}

測試代碼如下

public class SimpleFactoryTest {
 
	public static void main(String[] args) throws Exception {
		SimpleFactory factory = new SimpleFactory();
		System.out.println(factory.createCPU().getName());
		System.out.println(factory.createMainBoard().getName());
	}
}

我們看到,在調用的時候客戶端完全不用管用的是Intel還是AMD,這樣如果想切換產品族的話,只需要修改配置文件即可,非常的方便。

到此這篇關于Java設計模式之簡單工廠 工廠方法 抽象工廠深度總結的文章就介紹到這了,更多相關Java 設計模式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java集合Stream流操作的基本使用教程分享

    Java集合Stream流操作的基本使用教程分享

    流操作并不會影響原來的集合,可以簡單認為,流操作是把集合中的一個元素逐個復制放到一個首尾相接的流動的水槽中。這篇文章整理了Stream流操作的基本使用,需要的可以參考一下
    2023-02-02
  • java題解leetcode242.有效的字母異位詞

    java題解leetcode242.有效的字母異位詞

    這篇文章主要為大家介紹了java題解leetcode242.有效的字母異位詞方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • java如何根據時間戳生成有序ID

    java如何根據時間戳生成有序ID

    這篇文章主要介紹了java如何根據時間戳生成有序ID問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 使用java數組 封裝自己的數組操作示例

    使用java數組 封裝自己的數組操作示例

    這篇文章主要介紹了使用java數組 封裝自己的數組操作,結合實例形式分析了java數組索引、遍歷等相關封裝操作技巧與注意事項,需要的朋友可以參考下
    2020-03-03
  • mybatisplus?@Select注解中拼寫動態(tài)sql異常問題的解決

    mybatisplus?@Select注解中拼寫動態(tài)sql異常問題的解決

    這篇文章主要介紹了mybatisplus?@Select注解中拼寫動態(tài)sql異常問題的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 新手場景Java線程相關問題及解決方案

    新手場景Java線程相關問題及解決方案

    這篇文章主要介紹了新手場景Java線程相關問題及解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • java必學必會之this關鍵字

    java必學必會之this關鍵字

    java必學必會之this關鍵字,java中this的用法進行了詳細的分析介紹,感興趣的小伙伴們可以參考一下
    2015-12-12
  • java根據網絡地址保存圖片的方法

    java根據網絡地址保存圖片的方法

    這篇文章主要為大家詳細介紹了java根據網絡地址保存圖片的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • java9新特性Collection集合類的增強與優(yōu)化方法示例

    java9新特性Collection集合類的增強與優(yōu)化方法示例

    這篇文章主要為大家介紹了java9新特性Collection集合類的增強與優(yōu)化方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • Java實現對比兩個實體類字段變化的示例詳解

    Java實現對比兩個實體類字段變化的示例詳解

    我們在工作中,可能會在日志中記錄數據的變化情況或者在公共處理的數據增加一個日志頁面,我們可以根據CompareUtils工具類比較數據前后發(fā)生了怎樣的變化,下面我們就來看看具體實現吧
    2024-03-03

最新評論