爲了知足「開閉原則」,大部分設計模式都引入了抽象層,如工廠方法模式、抽象工廠模式、適配器模式、橋接模式、命令模式、策略模式等等。客戶端代碼針對抽象層編程,而在程序運行的時候再指定其子類,根據「里氏代換原則」和麪向對象的多態性,子類對象在運行時將覆蓋父類對象。若是須要對系統進行擴展或修改,只需修改子類類名便可。在具體實現時,經過引入配置文件可使得用戶在不修改任何客戶端代碼的前提下增長或替換子類,其基本實現過程以下:spring
(1)客戶端針對抽象層編程,客戶端代碼中不能出現任何具體類類名,即客戶端不直接實例化對象;
(2)引入純文本格式的配置文件,一般是XML文件,將具體類類名存儲在配置文件中;
(3)經過DOM(Document Object Model,文檔對象模型)、SAX(Simple API for XML)等XML解析技術獲取存儲在配置文件中的類名;
(4)在客戶端代碼中經過反射(Reflection)機制根據類名建立對象,用反射所建立的對象替換父類對象的引用,程序運行時,將調用子類方法來實現業務功能;
(5)若是須要擴展功能,只需增長一個新的子類繼承抽象父類,再修改配置文件,從新運行程序便可;若是須要替換功能,只需用另外一個子類類名替換存儲在配置文件中的原有子類類名便可。不管是擴展仍是替換都無須修改既有類庫和客戶端源代碼,徹底符合開閉原則。編程
新建一個對象來獲取配置屬性:設計模式
package com.atomview.signalgateway.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * Created on 2018/10/9. */ public class StreamServerProperties { @Value("#{propertiesReader['state']}") private String m_ConnectState; @Value("#{propertiesReader['server.ip']}") private String m_StreamserverIp; @Value("#{propertiesReader['server.port']}") private String m_StreamserverPort; public String getConnectState() { return m_ConnectState; } public String getStreamserverIp() { return m_StreamserverIp; } public String getStreamserverPort() { return m_StreamserverPort; } }
這裏面定義了5個IImageSelect接口的子類,經過定義好的泛型ImageSelectClientMode來決定實例化哪一個子類,如今遇到這麼一個問題,若是添加到第6個子類的話,那就必需要更改ImageSelectFactory類以及枚舉ImageSelectClientMode,雖不說影響不影響什麼開閉設計原則,可是有個狀況你可成想到,你這個類要打包發佈給別人的話,別人在沒有源碼的狀況下如何擴展呢?這裏就須要咱們動態的經過配置文件來加載實現類了。atom
經過讀取本地的.properties文件來獲取咱們須要實例化的類,而後經過反射來生成對象,這樣當你把發佈出去的時候,使用者只用更改配置文件就可讓工廠去實例化本身後來才寫的實現類,咱們看看實現方式:spa
經過讀取本地的.properties文件來獲取咱們須要實例化的類,而後經過反射來生成對象,這樣當你把發佈出去的時候,使用者只用更改配置文件就可讓工廠去實例化本身後來才寫的實現類,咱們看看實現方式:設計
public static class ImageSelectFactory { public static IImageSelect createIImageSelect(String type) { IImageSelect mIImageSelect; //實例化Properties對象,用於讀取.properties Properties properties = new Properties(); InputStream is = null; try { is = ImageSelectClient.class.getResourceAsStream("ImageSelectClient.properties"); //裝載ImageSelectClient.properties文件 properties.load(is); } catch (Exception e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } try { //根據key獲取value,value即爲將要實例化的類 Class<?> aClass = Class.forName(properties.getProperty(type)); //使用反射進行實例化 mIImageSelect = (IImageSelect) aClass.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return mIImageSelect; }
咱們就能夠隨便實現子類,而後在.properties文件中添加對應的包路徑,而後經過ImageSelectFactory就能夠進行實例化了。3d