簡單工廠模式 概念 簡單工廠模式屬於創建型模式,又叫做靜態工廠方法(Static Factory Method)。簡單工廠模式是由一個工廠對象決定創建哪一種產品類實例。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的 ...
簡單工廠模式
概念
簡單工廠模式屬於創建型模式,又叫做靜態工廠方法(Static Factory Method)。簡單工廠模式是由一個工廠對象決定創建哪一種產品類實例。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。簡單工廠模式是工廠模式家族中最簡單實用的模式,可以理解為不同工廠模式的一個特殊實現
值得註意的是,簡單工廠模式並不屬於GOF設計模式之一。但是他說抽象工廠模式,工廠方法模式的基礎,並且有廣泛得應用
模式結構
組成
從上圖中可以看出,簡單工廠模式由三部分組成:具體工廠、抽象產品和具體產品:
- 工廠類(Creator):這是本模式的核心,含有一定的商業邏輯和判斷邏輯。在java中,它往往由一個具體的類實現
- 抽象產品(AbstractProduct):它一般是具體產品繼承的父類或者實現的介面。在Java中,由介面或者抽象類實現
- 具體產品(ConcreteProduct):工廠類所創建的對象就是此角色的實例。在java中 由一個具體的類實現
實例分析
需求:有蘋果類和香蕉類,他們都有get方法,通過主函數對它們進行實例化,並調用get方法
方式一:最基本的實例化
Apple.java:
public class Apple {
/**
* 採集蘋果
*/
public void get(){
System.out.println("採集蘋果");
}
}
Banana.java:
public class Banana {
/**
* 採集香蕉
*/
public void get(){
System.out.println("採集香蕉");
}
}
MainClass.java:
public class Mainclass{
public static void main(String[] args){
/**
* 最基本的實例化方式
*/
//實例化一個Apple
Apple apple = new Apple();
//實例化一個Banana
Banana banana = new Banana();
apple.get();
banana.get();
}
}
方式二:都有get方法,我們可以用多態的方式抽象出一個介面類實現
Fruit.java:
public interface Fruit {
public void get();
}
Apple.java:
public class Apple implements Fruit{
@Override
//重寫get方法
public void get(){
System.out.println("採集蘋果");
}
}
Banana.java:
public class Banana implements Fruit{
@Override
//重寫get方法
public void get(){
System.out.println("採集香蕉");
}
}
MainClass.java:
public class Mainclass{
public static void main(String[] args){
/**
* 多態的實例化方式
*/
Fruit apple = FruitFactory.getApple();
Fruit banana = FruitFactory.getBanana();
apple.get();
banana.get();
}
}
方式三:新增一個工廠類實現對象的創建和主要邏輯
FruitFactory:
public class FruitFactory {
/**
* 獲得Apple類的實例
*/
public static Fruit getApple(){
return new Apple();
}
/**
* 獲得Banana類的實例
*/
public static Fruit getBanana(){
return new Banana();
}
}
Fruit.java:不變
public interface Fruit {
public void get();
}
Apple.java:不變
public class Apple implements Fruit{
@Override
//重寫get方法
public void get(){
System.out.println("採集蘋果");
}
}
Banana.java:不變
public class Banana implements Fruit{
@Override
//重寫get方法
public void get(){
System.out.println("採集香蕉");
}
}
MainClass.java:不變
public class Mainclass{
public static void main(String[] args){
/**
* 通過工廠類的靜態方法實例化
*/
Fruit apple = FruitFactory.getApple();
Fruit banana = FruitFactory.getBanana();
apple.get();
banana.get();
}
}
方式四:優化工廠類一,調用相同的方法,通過傳參的方式實例化
FruitFactory:
public class FruitFactory {
public static Fruit getFruit(String type) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
/**
* 對參數的判斷並返回實例
*/
if (type.equalsIgnoreCase("apple")){
return Apple.class.newInstance();
} else if (type.equalsIgnoreCase("banana")){
return Banana.class.newInstance();
} else {
System.out.println("找不到相應的實例化類");
return null;
}
}
}
Fruit.java:不變
public interface Fruit {
public void get();
}
Apple.java:不變
public class Apple implements Fruit{
@Override
public void get(){
System.out.println("採集蘋果");
}
}
Banana.java:不變
public class Banana implements Fruit{
@Override
public void get(){
System.out.println("採集香蕉");
}
}
MainClass.java:
public class Mainclass{
public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
Fruit apple = FruitFactory.getFruit("apple");
Fruit banana = FruitFactory.getFruit("banana");
apple.get();
banana.get();
}
}
方式五:優化工廠類二,通過反射類名進一步優化實例化過程
FruitFactory:
public class FruitFactory {
public static Fruit getFruit(String type) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
Class fruit = Class.forName(type);
return (Fruit)fruit.newInstance();
}
}
Fruit.java:不變
public interface Fruit {
public void get();
}
Apple.java:不變
public class Apple implements Fruit{
@Override
public void get(){
System.out.println("採集蘋果");
}
}
Banana.java:不變
public class Banana implements Fruit{
@Override
public void get(){
System.out.println("採集香蕉");
}
}
MainClass.java:
public class Mainclass{
public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
Fruit apple = FruitFactory.getFruit("Apple");
Fruit banana = FruitFactory.getFruit("Banana");
apple.get();
banana.get();
}
}
優點
- 工廠類含有必要的判斷邏輯,可以決定在什麼時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅“消費”產品;簡單工廠模式通過這種做法實現了對責任的分割,它提供了專門的工廠類用於創建對象
- 客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對於一些複雜的類名,通過簡單工廠模式可以減少使用者的記憶量
- 通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性
- 當需要引入新的產品是不需要修改客戶端的代碼,只需要添加相應的產品類並修改工廠類就可以了,所以說從產品的角度上簡單工廠模式是符合“開-閉”原則的
缺點
- 由於工廠類集中了所有產品創建邏輯,工廠類一般被我們稱作“全能類”或者“上帝類”,因為所有的產品創建他都能完成,這看似是好事,但仔細想想是有問題的。比如全國上下所有的事情都有國家主義一個人乾會不會有問題,當然有!一旦不能正常工作,整個系統都要受到影響
- 使用簡單工廠模式將會增加系統中類的個數,在一定程式上增加了系統的複雜度和理解難度
- 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護。所以說從工廠的角度來說簡單工廠模式是不符合“開-閉”原則的
- 簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構
適用場景
- 工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過複雜
- 客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數