簡述 類型:創建型 目的:實現對客戶端中對象族的平替。 對象族 一組對象。比如,華為的手機,筆記本,平板可以統稱為華為族。 我們藉以下案例來說說如何使用抽象工廠模式平替對象族。 優化案例 最初版 public interface Uploader { void upload(String fileN ...
簡述
-
類型:創建型
-
目的:實現對客戶端中對象族的平替。
對象族
一組對象。比如,華為的手機,筆記本,平板可以統稱為華為族。
我們藉以下案例來說說如何使用抽象工廠模式平替對象族。
優化案例
最初版
public interface Uploader {
void upload(String fileName);
}
public interface Downloader {
void download(String fileName);
}
public class LinuxUploader implements Uploader {
public void upload(String fileName) {
System.out.printf("[Linux]正在上傳%s...", fileName);
}
}
public class LinuxDownloader implements Downloader {
public void download(String fileName) {
System.out.printf("[Linux]正在下載%s...", fileName);
}
}
public class UnixUploader implements Uploader {
public void upload(String fileName) {
System.out.printf("[Unix]正在上傳%s...", fileName);
}
}
public class UnixDownloader implements Downloader {
public void download(String fileName) {
System.out.printf("[Unix]正在下載%s...", fileName);
}
}
客戶端調用如下。
public class Client {
public static void main(String[] args) {
Uploader uploader = new LinuxUploader();
Downloader downloader = new LinuxDownloader();
}
}
傳統是new創建對象的方式有著硬編碼的問題。當我們需要把所有LinuxXXX對象改為UnixXXX對象時,就必須在項目中檢索所有的LinuxXXX修改為UnixXXX。這無疑增加了大量的無意義的工作。
修改版v1(簡單工廠)
增加一個工廠類,其他不變。
public class Factory {
static Uploader uploader(String target) {
if ("LinuxUploader".equals(target)) {
return new LinuxUploader();
} else if ("UnixUploader".equals(target)) {
return new UnixUploader();
}
throw new Exception("輸入的參數錯誤");
}
static Downloader downloader(String target) {
if ("LinuxDownloader".equals(target)) {
return new LinuxDownloader();
} else if ("UnixDownloader".equals(target)) {
return new UnixDownloader();
}
throw new Exception("輸入的參數錯誤");
}
}
修改後,客戶端的代碼調用。
public class Client {
public static void main(String[] args) {
Uploader up1 = Factory.instance("LinuxUploader");
Downloader down1 = Factory.instance("LinuxDownloader");
Uploader up2 = Factory.instance("UnixUploader");
Downloader down2 = Factory.instance("UnixDownloader");
}
}
在一定程度上解決了客戶端硬編碼問題。並且當我們需要把所有LinuxUploader對象改為UnixUploader對象時,只需要在Factory中將new LinuxUploader() → new UnixUploader()
即可。這無疑節省了很多的時間,也無需為硬編碼帶來的大量改修而苦惱。
但是目前這個優化方案依然有至少兩個問題,一是Factory.uploader
方法中耦合了所有的Uploader實現類,這可能有礙於未來的項目維護,二是new LinuxUploader() → new UnixUploader()
這種修改方式會導致代碼目的不明確,既然不論是LinuxUploader還是UnixUploader都直接生成UnixUploader對象,就沒有必要定義LinuxUploader了呀。實際上是因為客戶端代碼中還有使用OSFactory.instance("LinuxUploader")
來創建的對象,為了不修改客戶端代碼,強行做如上修改。
修改版v2(抽象工廠)
將原本的工廠類抽象化,並定義一系列不同的實現類,其餘不變。
public interface Factory {
Uploader uploader();
Downloader downloader();
}
public class LinuxFactory {
public Uploader uploader() {
return new LinuxUploader();
}
public Downloader downloader() {
return new LinuxDownloader();
}
}
public class UnixFactory {
public Uploader uploader() {
return new UnixUploader();
}
public Downloader downloader() {
return new UnixDownloader();
}
}
修改後,客戶端的代碼調用。
public class Client {
private static Factory factory = new LinuxFactory();
public static void main(String[] args) {
Uploader uploader = factory.uploader();
Downloader downloader = factory.downloader();
}
}
將原本Factory
類中臃腫的邏輯分散到各個子類中,提高了系統的可維護性,不用再每次都修改Factory
類了。
那麼,問題來了,這樣的結構對於我們的項目有什麼幫助嗎?有,而且很大,在客戶端定義了一個靜態的屬性factory
,當接下來客戶換了系統從Linux換到了Unix,那我們也需要更換對應的上傳下載的類,這時我們只要修改factory引用的具體工廠類的對象就可以了,很方便。實際上還可以更加方便的實現對象族的平替。而為了實現這個需求,我們需要結合Java反射這項技術。請看下麵的代碼。
修改版v3(抽象工廠+反射)
只修改客戶端的調用方式,其他位置不做修改。
public class Client {
private static Factory factory;
static {
// 讀取prop配置文件
Properties prop = new Properties();
FileReader fileReader = new FileReader("src/resource/props/config.prop");
prop.load(fileReader);
fileReader.close();
factory = (Factory) Class.forName(prop.getProperty("FACTORY"))
.getDeclaredConstructor().newInstance();
}
public static void main(String[] args) {
Uploader uploader = factory.uploader();
Downloader downloader = factory.downloader();
}
}
增加一個properties文件文件,定義如下。
#當前使用的工廠類
FACTORY=design.abstractfactory.LinuxFactory
當需要將系統中的Linux
系列的對象轉化為Unix
系列時,只需要更改上述配置文件即可,具體如下。
#當前使用的工廠類
FACTORY=design.abstractfactory.UnixFactory
總之就是非常方便。
總結
優點
- 輕鬆做到對象族的平替。
缺點
- 類數量倍增,系統複雜度增加。
應用場景
- 根據需求,需要全面替換系統中的某個對象族時。
本文來自博客園,作者:buzuweiqi,轉載請註明原文鏈接:https://www.cnblogs.com/buzuweiqi/p/16703315.html