1. 程式人生 > 其它 >設計模式 - 抽象工廠模式

設計模式 - 抽象工廠模式

目錄

例項

手機軟體初始化

假設一個手機軟體初始化的應用場景,該軟體支援IOSAndroidWindows等多個作業系統平臺,針對不同的作業系統,該軟體提供了不同的操作功能(Operation)類和操作介面(Surface)類,並提供相應的工廠類來封裝這些類的初始化過程。軟體要求具有較好的擴充套件性以支援新的作業系統平臺

  • 軟體結構示意圖如下:

工廠方法模式解決方案

  • 初始解決方案採用工廠方法模式,大致如下:
  • Operation.java
/**
 * @Description 操作功能抽象類
 */
public abstract class Operation {
    public abstract void init();
}
  • AndroidOperation.java
/**
 * @Description Android操作功能產品類
 */
public class AndroidOperation extends Operation {
    @Override
    public void init() {
        System.out.println("初始化Android操作功能");
    }
}
  • IOSOperation.java
/**
 * @Description IOS操作功能產品類
 */
public class IOSOperation extends Operation {
    @Override
    public void init() {
        System.out.println("初始化IOS操作功能");
    }
}
  • OperationFactory.java
/**
 * @Description 操作功能工廠類(工廠方法模式)
 */
public interface OperationFactory {
    Operation getOperation();
}
  • AndroidOperationFactory.java
/**
 * @Description Android操作功能工廠類
 */
public class AndroidOperationFactory implements OperationFactory {
    @Override
    public Operation getOperation() {
        return new AndroidOperation();
    }
}
  • IOSOperationFactory.java
/**
 * @Description IOS操作功能工廠類
 */
public class IOSOperationFactory implements OperationFactory {
    @Override
    public Operation getOperation() {
        return new IOSOperation();
    }
}
  • Test.java
/**
 * @Description 工廠方法模式測試類
 */
public class Test {
    public static void main(String[] args) {
        OperationFactory operationFactory = new AndroidOperationFactory();
        Operation operation = operationFactory.getOperation();
        operation.init();

        operationFactory = new IOSOperationFactory();
        operation = operationFactory.getOperation();
        operation.init();
    }
}
  • 輸入如下:
初始化Android操作功能
初始化IOS操作功能
  • 操作介面抽象程式碼類似,不一一貼上,完整類圖如下所示:
  • 通過類圖不難看出,此設計方案當需要支援新的作業系統平臺時雖不需要修改現有程式碼,但類的增加是爆炸的,針對每一個新的作業系統的支援都需要增加新的抽象工廠和具體工程,類的個數成對增加,最後導致系統越來越龐大
  • 在工廠方法模式中,具體工廠負責生產具體的產品,每個具體工廠對應一種具體產品,工廠方法具有唯一性,顯然,例項所處的業務場景是具有多個產品物件的,並不是單一的產品物件
  • 當系統所提供的工廠生產的具體產品並不是一個單一產品,而是多個位於不同產品等級結構、屬於不同型別的具體產品時,就可以使用抽象工廠模式

  • 抽象工廠模式示意圖如下:
  • 產品等級結構:產品的繼承結構
  • 產品族:指同一個工廠生產的位於不同產品等級結構中的一組產品

抽象工廠模式

概念

  • 抽象工廠模式(Abstract Factory Pattern),提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類
  • 抽象工廠模式又稱為Kit模式,它是一種物件建立型模式

抽象工廠模式解決方案

  • Operation.java
/**
 * @Description 操作功能抽象類
 */
public abstract class Operation {
    public abstract void init();
}
  • AndroidOperation.java
/**
 * @Description Android操作功能產品類
 */
public class AndroidOperation extends Operation {
    @Override
    public void init() {
        System.out.println("初始化Android操作功能");
    }
}
  • IOSOperation.java
/**
 * @Description IOS操作功能產品類
 */
public class IOSOperation extends Operation {
    @Override
    public void init() {
        System.out.println("初始化IOS操作功能");
    }
}
  • Surface.java
/**
 * @Description 操作介面抽象類
 */
public abstract class Surface {
    public abstract void init();
}
  • AndroidSurface.java
/**
 * @Description Android操作介面產品類
 */
public class AndroidSurface extends Surface {
    @Override
    public void init() {
        System.out.println("初始化Android操作介面");
    }
}
  • IOSSurface.java
/**
 * @Description IOS操作介面產品類
 */
public class IOSSurface extends Surface {
    @Override
    public void init() {
        System.out.println("初始化IOS操作介面");
    }
}
  • InitFactory.java
/**
 * @Description 初始化工廠介面:抽象工廠
 */
public interface InitFactory {
    Operation getOperation();
    Surface getSurface();
}
  • AndroidInitFactory.java
/**
 * @Description Android初始化工廠:具體工廠類
 */
public class AndroidInitFactory implements InitFactory{
    @Override
    public Operation getOperation() {
        return new AndroidOperation();
    }

    @Override
    public Surface getSurface() {
        return new AndroidSurface();
    }
}
  • IOSInitFactory.java
/**
 * @Description IOS初始化工廠:具體工廠類
 */
public class IOSInitFactory implements InitFactory{
    @Override
    public Operation getOperation() {
        return new IOSOperation();
    }

    @Override
    public Surface getSurface() {
        return new IOSSurface();
    }
}
  • Test.java
/**
 * @Description 抽象工廠測試類
 * @author coisini
 * @date Mar 4, 2022
 * @version 1.0
 */
public class Test {
    public static void main(String[] args) {
        InitFactory initFactory = new AndroidInitFactory();
        Operation operation = initFactory.getOperation();
        Surface surface = initFactory.getSurface();
        operation.init();
        surface.init();

        initFactory = new IOSInitFactory();
        operation = initFactory.getOperation();
        surface = initFactory.getSurface();
        operation.init();
        surface.init();
    }
}
  • 輸入如下:
初始化Android操作功能
初始化Android操作介面
初始化IOS操作功能
初始化IOS操作介面
  • 類圖如下:
  • 抽象工廠可以將一組具有同一主題單獨的工廠封裝起來
  • 抽象工廠模式與工廠方法模式最大的區別在於:工廠方法模式針對的是一個產品等級結構,而抽象工廠模式需要面對多個產品等級結構
  • 當一個工廠等級結構可以創建出分屬於不同產品等級結構的一個產品族中的所有物件時,抽象工廠模式比工廠方法模式更為簡單、更有效率

方案的演進(配置檔案)

  • 如上客戶端Test.java呼叫程式碼還具有可改進的地方,可通過配置檔案 + 反射實現在不修改客戶端程式碼的基礎上更換和擴充套件對作業系統的支援

  • config.properties

abstractFactory.className=AndroidInitFactory
  • PropertiesUtil.java
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * @Description Properties工具類
 * @author coisini
 * @date Feb 28, 2022
 * @version 1.0
 */
public class PropertiesUtil {

    /**
     * 根據key讀取value
     * @Description: 相對路徑, properties檔案需在classpath目錄下,
     *               比如:config.properties在包com.coisini.util,
     *               路徑就是/com/coisini/util/config.properties
     * @param filePath
     * @param keyWord
     * @return String
     * @throws
     */
     private static String getProperties(String filePath, String keyWord){
        Properties prop = new Properties();
        String value = null;
        try {
            InputStream inputStream = PropertiesUtil.class.getResourceAsStream(filePath);
            prop.load(inputStream);
            value = prop.getProperty(keyWord);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return value;
     }

    /**
     * 根據配置檔案提取類名返回例項物件
     * @param filePath
     * @param keyWord
     * @param packagePath
     * @return
     */
     private static Object getBean(String filePath, String keyWord, String packagePath) {
         try {
             String className = getProperties(filePath, keyWord);
             Class<?> c = Class.forName(packagePath + className);
             return c.newInstance();
         } catch (Exception e) {
             e.printStackTrace();
             return null;
         }

     }

    /**
     * 獲取抽象工廠例項物件
     * @return
     */
    public static Object getAbstractFactoryBean() {
        return getBean("/com/coisini/design/util/config.properties",
                "abstractFactory.className",
                "com.coisini.design.pattern.creational.abstractfactory.v3.");
    }
}
  • Test.java
/**
 * @Description 抽象工廠測試類
 */
public class Test {
    public static void main(String[] args) {
        InitFactory initFactory = (InitFactory) PropertiesUtil.getAbstractFactoryBean();
        Operation operation = initFactory.getOperation();
        Surface surface = initFactory.getSurface();
        operation.init();
        surface.init();
    }
}
  • 通過如上配置檔案 + 反射實現方式,客戶端程式碼無需使用new關鍵字來建立工廠物件,而是將具體工廠類的類名存在配置檔案中,通過讀取配置檔案獲取類名字串,再使用反射機制根據類名字串生成物件

總結

  • 優點
1、具體產品在應用層程式碼隔離,無需關心建立細節
2、將一個系列的產品族統一到一起建立
  • 缺點
1、規定了所有可能被建立的產品集合,產品族中擴充套件新的產品困難,需要修改抽象工廠的介面
2、增加了系統的抽象性和理解難度
  • 適用場景
1、客戶端(應用層)不依賴於產品類例項如何被建立、實現等細節
2、強調一系列相關的產品物件(屬於同一產品族)一起使用建立物件需要大量重複的程式碼
3、提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於具體實現

原始碼


- End -
- 個人學習筆記 -

以上為本篇文章的主要內容,希望大家多提意見,如果喜歡記得點個推薦哦 作者:Maggieq8324 出處:https://www.cnblogs.com/maggieq8324/ 本文版權歸作者和部落格園共有,歡迎轉載,轉載時保留原作者和文章地址即可。