在項目的開發中,咱們很難作到開發一套標準的流程來解決全部客戶的需求。好比,咱們當前的計量項目,分別運行於赤峯市和河北省。雖然兩個區域處理的業務相同,可是對細節的實現要求卻不一樣。前面也學習過計量檢定軟件,其爲了解決各個定製者使用的功能需求,最後採起的方案是:將基礎項目複製多份,進而知足不一樣的客戶需求。優勢固然是有的,但比起缺點來,優勢便不值一提。缺點很明顯,總結爲一句話就是:項目變得難以維護。因此,當前讓咱們看到的就是,幾個開發人員,天天處於解決問題當中。本文將給出一種方案,來有效的規避上述問題。java
示例代碼:https://github.com/mengyunzhi/springBootSampleCode/tree/master/dynamic-autowiregit
開發環境:java1.8 + spring-boot:2.1.3.RELEASE
你好
或hello
Hallo
。增長功能時,不更改核心代碼。注意:若是你看完需求假設後,毫無觸動,請忽略本文如下內容github
解決方案中,咱們涉及了兩種設計模塊,分別爲:策略模式
及工廠模式
。
策略模式:通常用於將具體的算法
進行抽象及剝離。此項目中,咱們的具體算法是說你好
。
工廠模式:通常用於根據環境來動態的建立BEAN的狀況下。引項目中,咱們將根據不一樣國家的人,來返回不一樣的說你好
這個算法。算法
先給出UML圖:
spring
SpeakService
即爲咱們供其它模塊調用的說話服務
,調用其中的SayHello()
來完成說你好
功能。設計模式
package com.mengyunzhi.demo.dynamicautowire; /** * 你好 */ public interface SpeakService { void sayHello(); }
在其實現類中,咱們注入SayHelloFactory
,讓其來返回正確的SayHelloService
,最終調用sayHello()
來完成目標。ide
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 你好 */ @Service public class SpeakServiceImpl implements SpeakService { private final SayHelloFactory sayHelloFactory; // 說話工廠 @Autowired public SpeakServiceImpl(SayHelloFactory sayHelloFactory) { this.sayHelloFactory = sayHelloFactory; } @Override public void sayHello() { this.sayHelloFactory.getSayHelloService().sayHello(); } }
package com.mengyunzhi.demo.dynamicautowire; /** * 說話工廠 */ public interface SayHelloFactory { void setCountryCode(CountryCode countryCode); SayHelloService getSayHelloService(); }
在此,咱們增長一個CountryCode
表示當前訪問者的國家。其實在獲取訪問者國家時,咱們也能夠調用其它Bean的其它來實現。spring-boot
package com.mengyunzhi.demo.dynamicautowire; /** * 國家代碼 */ public enum CountryCode { CHINA((byte) 0, "中國"), USA((byte) 1, "美國"); private Byte code; private String name; CountryCode(Byte code, String name) { this.code = code; this.name = name; } public Byte getCode() { return code; } public String getName() { return name; } }
使用enum
來控制範圍,避免Factory
在獲取Bean時發生異常。單元測試
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 說話工廠 */ @Service public class SayHelloFactoryImpl implements SayHelloFactory { /** * BEAN列表 */ private final Map<Byte, SayHelloService> servicesByCode = new HashMap<>(); /** * 國家代碼 */ private CountryCode countryCode = CountryCode.CHINA; @Override public void setCountryCode(CountryCode countryCode) { this.countryCode = countryCode; } /** * 初始化 * * @param sayHelloServices spring獲取到的因此實現了SpeakService的BEAN */ @Autowired public void init(List<SayHelloService> sayHelloServices) { for (SayHelloService sayHelloService : sayHelloServices) { this.register(sayHelloService.getCode(), sayHelloService); } } /** * 註冊Bean * * @param code 代碼 * @param sayHelloService BEAN */ private void register(Byte code, SayHelloService sayHelloService) { this.servicesByCode.put(code, sayHelloService); } /** * 獲取BEAN * * @return 對應的SayHelloService BEAN */ @Override public SayHelloService getSayHelloService() { return this.servicesByCode.get(this.countryCode.getCode()); } }
增長Map<Byte, SayHelloService> servicesByCode
來存儲對應國家的SayHelloService
BEAN。增長getSayHelloService()
來根據當前國家代碼來返回相應的Bean。學習
package com.mengyunzhi.demo.dynamicautowire; /** * 說話 */ public interface SayHelloService { void sayHello(); Byte getCode(); }
將sayHello()
方法抽離,getCode()
以獲取國家代碼。
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.stereotype.Component; /** * 中國話 */ @Component public class SayHelloServiceChineseImpl implements SayHelloService { @Override public void sayHello() { System.out.println("您好"); } @Override public Byte getCode() { return CountryCode.CHINA.getCode(); } }
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.stereotype.Component; /** * 美國話 */ @Component public class SayHelloServiceEnglishImpl implements SayHelloService { @Override public void sayHello() { System.out.println("hello"); } @Override public Byte getCode() { return CountryCode.USA.getCode(); } }
package com.mengyunzhi.demo.dynamicautowire; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest @RunWith(SpringRunner.class) public class SpeakServiceImplTest { @Autowired SpeakService speakService; @Autowired SayHelloFactory sayHelloFactory; @Test public void sayHello() { // 默認說你好 speakService.sayHello(); // 將國家設置爲美國,再說你好 sayHelloFactory.setCountryCode(CountryCode.USA); speakService.sayHello(); // 將國家設置爲中國,再說你好 sayHelloFactory.setCountryCode(CountryCode.CHINA); speakService.sayHello(); } }
您好 hello 您好
SayHelloServiceGermanyImpl
.CountryCode
中,增長德國.package com.mengyunzhi.demo.dynamicautowire; import org.springframework.stereotype.Component; @Component public class SayHelloServiceGermanyImpl implements SayHelloService { @Override public void sayHello() { System.out.println("Hallo"); } @Override public Byte getCode() { return CountryCode.GERMANY.getCode(); } }
package com.mengyunzhi.demo.dynamicautowire; /** * 國家代碼 */ public enum CountryCode { CHINA((byte) 0, "中國"), USA((byte) 1, "美國"), GERMANY((byte) 2, "德國"); private Byte code; private String name; CountryCode(Byte code, String name) { this.code = code; this.name = name; } public Byte getCode() { return code; } public String getName() { return name; } }
@Test public void sayHello1() { // 默認說你好 speakService.sayHello(); // 將國家設置爲美國,再說你好 sayHelloFactory.setCountryCode(CountryCode.USA); speakService.sayHello(); // 將國家設置爲德國,再說你好 sayHelloFactory.setCountryCode(CountryCode.GERMANY); speakService.sayHello(); // 將國家設置爲中國,再說你好 sayHelloFactory.setCountryCode(CountryCode.CHINA); speakService.sayHello(); }
測試結果以下:
您好 hello Hallo 您好
在解決問題時,只全部咱們看的不夠遠,多是因爲本身站的不夠高。一樣的問題,困惑我了多日,直到近期系統的學習設計模式
、angular官方教程
、Spring 實戰
後,結合近期項目變動帶來的新需求,纔在使用設計模式解決此問題上有所啓發。
欲窮千里目,更上一層樓 唐·王之渙·《登鸛雀樓》