Spring通过注解优雅实现工厂模式
工厂模式作为开发者,应该都是耳熟能详的,在课本上、在网络上都会有无数的案例,是一个简单、确十分好用的设计模式。但是实现它的方法有很多,早年见过最多的就是用 if 判断类型,然后返回不同的实现类。后来见过在数据库写上类型和实现类的对应关系,然后通过 getBean 动态获取。
讲实话从个人角度并不推荐这两种实现方式,方案一 :每次新增类型和实现类后还需要去对应工厂类新增映射关系,如果类型太多,看起来也很不优雅;方案二:大多数情况下所谓的灵活都是 伪需求,正常每个类型对应的实现类都是绑死的,一般不会去修改类型和实现类的对应关系,如果将这个关系维护到数据库中,就是为了一个 这辈子都用不上的所谓的灵活,我认为大可不必,这只会对代码阅读 带来更多的障碍。
不优雅的工厂
废话不多说,直接来看看目前见过的比较多的 不优雅 的工厂。
定义接口 DevelopmentEngineerService
public interface DevelopmentEngineerService {
void writeCode(String codeDesc);
}
定义抽象类 AbstractDevelopmentEngineerService
@Slf4j
@Service
public abstract class AbstractDevelopmentEngineerService implements DevelopmentEngineerService{
@Override
public void writeCode(String codeDesc) {
log.info("{} 实现了{},{}", getLevel(),codeDesc,getResult());
}
public abstract String getLevel();
public abstract String getResult();
}
多态实现
LowDevelopmentEngineerService
@Service
public class LowDevelopmentEngineerService extends AbstractDevelopmentEngineerService{
@Override
public String getLevel() {
return "初级工程师:花费两天";
}
@Override
public String getResult() {
return "一堆BUG";
}
}
MiddleDevelopmentEngineerService
@Service
public class MiddleDevelopmentEngineerService extends AbstractDevelopmentEngineerService{
@Override
public String getLevel() {
return "中级工程师:花费三天";
}
@Override
public String getResult() {
return "成功上线";
}
}
HighDevelopmentEngineerService
@Service
public class HighDevelopmentEngineerService extends AbstractDevelopmentEngineerService{
@Override
public String getLevel() {
return "高级工程师:让中级工程师花费三天";
}
@Override
public String getResult() {
return "成功上线";
}
}
工厂类 FactoryDevelopmentEngineerService
@Service
public class FactoryDevelopmentEngineerService {
@Autowired
private LowDevelopmentEngineerService lowDevelopmentEngineerService;
@Autowired
private MiddleDevelopmentEngineerService middleDevelopmentEngineerService;
@Autowired
private HighDevelopmentEngineerService highDevelopmentEngineerService;
public DevelopmentEngineerService getDevelopmentEngineerService(String type) {
if ("low".equals(type)){
return lowDevelopmentEngineerService;
} else if ("middle".equals(type)) {
return middleDevelopmentEngineerService;
}else if ("high".equals(type)){
return highDevelopmentEngineerService;
}else {
throw new RuntimeException("开发工程师类型异常");
}
}
}
测试类与测试结果
public class DevelopmentEngineerServiceTest extends UicServiceApplicationTest {
@Autowired
private FactoryDevelopmentEngineerService developmentEngineerService;
@Test
public void writeCode(){
developmentEngineerService.getDevelopmentEngineerService("low").writeCode("用户注册/登录");
developmentEngineerService.getDevelopmentEngineerService("middle").writeCode("用户注册/登录");
developmentEngineerService.getDevelopmentEngineerService("high").writeCode("用户注册/登录");
}
}
对于以上代码,写的很好,实现了我们需要的功能、也成功的使用了工厂模式,但是我总觉得不够优雅,如果我的类型多达30个,那就要在上面注入30个对象,下面再写上一堆判断?是不是显得代码十分臃肿?
优雅的工厂模式
本质上SpringBoot的便捷和它对的 注解 的应用,是密不可分的。所以我们需要学会如何使用它。以带来更快地开发效率、更简介的代码行,以及看起来更加优雅的实现。
接口和抽象类不变 我就不重复贴代码了
多态实现
LowDevelopmentEngineerService
@Service("low")
public class LowDevelopmentEngineerService extends AbstractDevelopmentEngineerService{
@Override
public String getLevel() {
return "初级工程师:花费两天";
}
@Override
public String getResult() {
return "一堆BUG";
}
}
MiddleDevelopmentEngineerService
@Service("middle")
public class MiddleDevelopmentEngineerService extends AbstractDevelopmentEngineerService{
@Override
public String getLevel() {
return "中级工程师:花费三天";
}
@Override
public String getResult() {
return "成功上线";
}
}
HighDevelopmentEngineerService
@Service("high")
public class HighDevelopmentEngineerService extends AbstractDevelopmentEngineerService{
@Override
public String getLevel() {
return "高级工程师:让中级工程师花费三天";
}
@Override
public String getResult() {
return "成功上线";
}
}
注:这里 @Service注解里面有一个 value 属性,而此处则正是利用了这个 value 属性去进行标记
工厂类 FactoryDevelopmentEngineerService
@Service
public class FactoryDevelopmentEngineerService {
// 根据类型注入 将DevelopmentEngineerService 的所有实现类都注入,map的key 就是 对应service顶部注解的 value 值
@Autowired
private Map<String, DevelopmentEngineerService> serviceMap = new ConcurrentHashMap<>();
public DevelopmentEngineerService getDevelopmentEngineerService(String type) {
DevelopmentEngineerService service = serviceMap.get(type);
if (service == null) {
throw new RuntimeException("开发工程师类型异常");
}
return service;
}
}
通过这种实现方式我们可以确保 实现类和对应类型的映射关系维护在同一个Java 类文件中,并且无论如何新增/修改实现类都不需要再去调整工厂类。代码简介明了。
测试类与测试结果
public class DevelopmentEngineerServiceTest extends UicServiceApplicationTest {
@Autowired
private FactoryDevelopmentEngineerService developmentEngineerService;
@Test
public void writeCode(){
developmentEngineerService.getDevelopmentEngineerService("low").writeCode("用户注册/登录");
developmentEngineerService.getDevelopmentEngineerService("middle").writeCode("用户注册/登录");
developmentEngineerService.getDevelopmentEngineerService("high").writeCode("用户注册/登录");
}
}