在项目的开发中,咱们很难作到开发一套标准的流程来解决全部客户的需求。好比,咱们当前的计量项目,分别运行于赤峰市和河北省。虽然两个区域处理的业务相同,可是对细节的实现要求却不一样。前面也学习过计量检定软件,其为了解决各个定制者使用的功能需求,最后采起的方案是:将基础项目复制多份,进而知足不一样的客户需求。优势固然是有的,但比起缺点来,优势便不值一提。缺点很明显,总结为一句话就是:项目变得难以维护。因此,当前让咱们看到的就是,几个开发人员,天天处于解决问题当中。本文将给出一种方案,来有效的规避上述问题。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 实战
后,结合近期项目变动带来的新需求,才在使用设计模式解决此问题上有所启发。
欲穷千里目,更上一层楼 唐·王之涣·《登鹳雀楼》