面試官:小夥子,夠了夠了,一個工廠模式你都在這說半個小時了!
前言
創建型模式、主要用於解決Java對象的創建問題
工廠模式
工廠模式的說明
在面向對象的編程中,繼承和多態的概念實現了父類與子類之間的(is-A)關係
基於這種關係實現了子類的多態性,這種抽象的方式為子類提供了相同的操作並且支援子類的功能性拓展。但是出現了這樣的問題?
Verhicle verhicle = new Car();
Verhicle verhicle = new Truck();
problem所在:
- 子類複寫了父類的方法,那麼子類實例化父類對象時,就必須每一個子類都要進行。這樣就造成了對於不同的子類要調用不同的構造器去實例化父類對象。缺乏統一性操作。
- 另外從上面的兩行程式碼可以看出子類與父類之間的依賴關係、耦合度高
- 違反了父類的開閉原則和子類的單一職責原則
簡單工廠模式的引入,實現邏輯的封裝,使用公共的工廠類實現統一創建對象實例化父類的行為。
簡單工廠模式
- 簡單工廠實現的三種方式
- 靜態工廠模式
- 使用反射機制進行類註冊
- 使用newInstance方法進行類註冊
簡單工廠的UML圖
- 靜態工廠模式的解決方式:
創建一個單獨的verhicle簡單工廠類。通過內置枚舉儲存所有需要創建實例的子類,並通過統一的create(type)方法根據傳入參數的類型實現按需創建實例。
public class VerhicleFactory {
public enum VerhicleType {
Car,Truck,Boat;
}
public static Verhicle create(VerhicleType type) {
if(type.equals(VerhicleType.Car)) {
return new Car();
}
if(type.equals(VerhicleType.Truck)) {
return new Truck();
}
if(type.equals(VerhicleType.Boat)) {
return new Boat();
}
else return null;
}
}
優勢:
這種額外使用工廠類的方式,解決了上面子類實例化父類的破壞單一職責原則、實現了構造實例的統一性操作。
缺點:
可以從存儲的枚舉看出,一旦新增拓展的子類就必須修改工廠的枚舉,破壞了工廠類自身的開閉原則。
仍然沒有解決父類的對內關閉的對外拓展的開閉原則。
- 使用反射機制進行類註冊的解決方式
為了解決靜態工廠模式破壞自身開閉原則的弊端、我們可以使用反射機制使得註冊的新類在使用時被實例化。從而保證了對外拓展開發,對內修改閉合。也就是說即使新增對父類拓展的子類,也不再重新修改靜態工廠內的枚舉。
//服務端
public class Product {/*類體內容*/}
public class Product1 extends Product {}
/*...更多的拓展子類...*/
public class MoreProducts extends Product {}
/*使用反射機制進行類註冊的簡單工廠模式*/
private Map<String,Class> registeredProduct = new
HashMap<String,Class>();
/**實現對拓展子類的註冊、所有的拓展子類將會被記錄在Map集合中
*@parameter
* productId子類ID也就是子類的類型,對應靜態工廠的枚舉類型
* productClass子類的類對象,也就是子類的Class對象
*/
public void registerProduct(String productId, Class productClass) {
registeredProduct.put(productId, productClass);
}
/**更具傳入的子類類型、構造對應的子類實例並返回
*@parameter
* ProductType子類類型和上面的子類ID一致,對應靜態工廠的枚舉類型
*/
public Product createProduct(String ProductType) throws InstantiationException,IllegalAccessException {
Class productClass = registeredProduct.get(ProductType);
return (Product) productClass.newInstance();
}
//客戶端就依據相應的方法,進行類的註冊和實例創建
優點:
解決了靜態工廠類破壞開閉原則的弊端,把註冊和創建實例分開實現註冊的類在使用時才實例化。
缺點:
反射機制影響了程式性能、使用多了的話,程式性能肯定要低效很多。
- 使用newInstance方法進行類註冊的簡單工廠模式
只是基於上面反射機制進行類註冊的思想進行了一個小的修改:
- 避免使用反射機制、提高性能
- 如何實現呢?
- Map集合中不在存儲Class對象,而是已經創建的子類實例
- 基類中創建一個抽象方法
- 子類全部複寫、方法體是創建子類對象
- 這樣就可以實現上面Map集合存儲的時已經創建的子類實例
//服務端
public abstract class Product {
Product newInstance();
}
public class Product1 extends Product {}
/*...更多的拓展子類...*/
public class MoreProducts extends Product {
@override
public MoreProducts newInstance() {
return new MoreProducts();
}
}
/*使用反射機制進行類註冊的簡單工廠模式*/
private Map<String,Product> registeredProduct = new
HashMap<String,Product>();
/**實現對拓展子類的註冊、所有的拓展子類將會被記錄在Map集合中
*@parameter
* productId子類ID也就是子類的類型,對應靜態工廠的枚舉類型
* productClass子類的類對象,也就是子類的Class對象
*/
public void registerProduct(String productId, Product productType) {
registeredProduct.put(productId, productType);
}
/**更具傳入的子類類型、構造對應的子類實例並返回
*@parameter
* ProductType子類類型和上面的子類ID一致,對應靜態工廠的枚舉類型
*/
public Product createProduct(String ProductId) throws InstantiationException,IllegalAccessException {
Product productType = registeredProduct.get(ProductId);
return (Product) productType.newInstance();
}
//客戶端就依據相應的方法,進行類的註冊和實例創建
優點:
把基類之間劃為抽象類,解決了父類的開閉原則和子類的單一職責原則。支援了創建對象的統一性操作。
缺點:
類之間的繼承關係造成程式碼依然耦合度高的問題。
仍然存在未實現父類對內修改閉合的風險。
工廠方法模式
工廠方法模式的UML圖
解決方式:
-
服務端把產品介面化、對於所有需要拓展的產品可以直接實現統一介面方法,以及自定義方法。
-
另外抽象化工廠、可以將產品的服務化功能集成在抽象工廠,並且內置構造實例的抽象方法。那麼所有的拓展產品的工廠類都可以繼承實現對應的構造方法和功能。
// sever
public interface Product{
void features(); //定義統一的功能
}
public class Product1 implements Product {/*實現統一介面方法、以及自定義方法*/}
public class MoreProducts implements Product {/*實現統一介面方法、以及自定義方法*/}
/*工廠方法*/
public abstract class AbastractFactory {
Product create(); //定義統一構造器
void sever(){/*相應的統一服務功能*/}
}
public class Product1Factory implements AbstractFactory {/*實現構造器*/}
public class MoreProductsFactory extends AbstractFactory {/*實現構造器*/}
優勢:
將產品解耦,並且每一個拓展產品都有相應的工廠類實現對應的構造實例以及服務功能
缺點:
易造成工廠的冗餘、拓展產品過多時出現工廠類增多。
抽象工廠模式
解決方法:
在工廠方法模式的基礎之上、在抽象工廠中不再單獨創建統一的構造器,而是創建一類或者所有的拓展產品構造器。這樣工廠類繼承的時候只需要少了的繼承就可以完成多個拓展產品的構造任務。
// sever
public interface Product{
void features(); //定義統一的功能
}
public class Product1 implements Product {/*實現統一介面方法、以及自定義方法*/}
public class MoreProducts implements Product {/*實現統一介面方法、以及自定義方法*/}
/*抽象工廠模式*/
public abstract class AbastractFactory {
Product createProduct1(); //定義Product1構造器
Product createMoreProducts(); //定義MoreProducts構造器
void sever(){/*相應的統一服務功能*/}
}
public class ProductFactory extends AbstractFactory {/*實現對應構造器*/}
優點:
減少了工廠類的數量、避免冗餘問題
最後
歡迎關注公眾號:前程有光,領取一線大廠Java面試題總結+各知識點學習思維導+一份300頁pdf文檔的Java核心知識點總結!