1、过多使用 If Else 的不足
在日常的项目开发中,可能有这么一种场景,例如,有一个产品接口ProductService,业务中具体的产品如水果产品、电子产品等等去实现这个接口,重写不同的方法,在业务中对这块的调用,需要通过一个类型参数去获取到ProductService的不同实现类,得到不同产品。如果业务中使用IF else去根据类型参数获取不同的是实现类,随着业务的快速发展,最终的代码会变成如下:
/**
* @author HW
* 产品相关Controller
*/
@RestController
@RequestMapping("/product")
public class ProductController {
/**
* 水果产品Service组件
*/
@Resource
private ProductService fruitsProductService;
/**
* 电子产品Service组件
*/
@Resource
private ProductService electronicsProductService;
......(更多,略)
@GetMapping("/buyProduct")
public String buyProduct(@RequestParam("productType")String productType){
String product = "";
if ("fruitsProductService".equals(productType)) {
product = fruitsProductService.orderingProduct();
} else if ("electronicsProductService".equals(type)) {
product = electronicsProductService.orderingProduct();
}else if ("..".equals(type)) {
product = electronicsProductService.orderingProduct();
}else if ("..".equals(type)) {
product = electronicsProductService.orderingProduct();
}else if ("..".equals(type)) {
product = electronicsProductService.orderingProduct();
}else if ("..".equals(type)) {
product = electronicsProductService.orderingProduct();
}else if ("..".equals(type)) {
product = electronicsProductService.orderingProduct();
}
......(更多else if,略)
return StringUtils.isEmpty(product) ? "购买产品失败...." : product;
}
}
过多的 If Else,让人一眼看下去有点密集恐惧症,并且不容易维护。
那么问题来了,如何解决这种不足?我们先来看看工厂+策略模式适用场景:
“工厂+策略模式” 比较适合通过某些参数,去执行不同的业务逻辑的这种场景,能很好的解决执行逻辑相同,调用上游接口逻辑不同这种情形。这不就正是我们需要的解决方案。
2、Spring Boot+工厂+策略模式实战
2.1、项目依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.2、配置文件application.yml
server:
port: 8082
2.3、产品接口类 (即策略接口类)
产品的接口类,该类就相当于策略模式中的接口类,里面定义一个策略的方法定义,子类会实现该策略方法。不过不同的是,这里接口类中定义的一种产品购买的方法,不同的子类来实现不同产品订购的方法。
/**
* 产品相关Service接口
* @author HW
*/
public interface ProductService {
/**
* 购买产品
* @return 返回结果
*/
String buyProduct();
}
水果产品实现类:
/**
* 水果产品实现类
* @author HW
*/
@Service("fruitsProductService")
public class FruitsProductServiceImpl implements ProductService {
/**
* 购买水果相关的产品
* @return 返回结果
*/
@Override
public String buyProduct() {
System.out.println("fruitsProductService is success.....");
return "fruitsProductService is success.....";
}
}
电子产品实现类:
/**
* 电子相关产品实现了
* @author HW
*/
@Service("electronicsProductService")
public class ElectronicsProductServiceImpl implements ProductService {
/**
* 购买电子相关产品
* @return 返回结果
*/
@Override
public String buyProduct() {
System.out.println("electronicsProductService is success.......");
return "electronicsProductService is success.......";
}
}
创建工厂类:
/**
* @author HW
* 产品工厂
*/
@Component
public class ProductStrategyFactory {
/**
* 使用依赖注入引入ProductService产品实现类,
* 以 Bean名称作为 Map的 Key,以Bean实现类作为 Value
*/
@Resource
private Map<String, ProductService> strategyMap = new ConcurrentHashMap<>();
/**
* 查找对应的产品的处理策略
*
* @param productName 产品名称
* @return 对应的产品购买逻辑实现策略
*/
public ProductService getProductStrategy(String productName) {
System.out.println(strategyMap.toString());
// 根据从 productName 从 strategyMap 集合中查询对应的产品下单策略
return strategyMap.get(productName);
}
}
产品Controller类:
获取不同的产品下单实现类,然后调用不同的产品下单实现类去执行下单购买的业务逻辑。
/**
* @author HW
* 产品相关Controller
*/
@RestController
@RequestMapping("/product")
public class ProductController {
@Resource
private ProductStrategyFactory productStrategyFactory;
@GetMapping("/buyProduct")
public String buyProduct(@RequestParam("productType")String productType){
ProductService productStrategy = productStrategyFactory.getProductStrategy(productType);
String product = "";
if (Objects.nonNull(productStrategy)){
product = productStrategy.buyProduct();
}
return StringUtils.isEmpty(product) ? "购买产品失败...." : product;
}
}
2.4、SpringBoot 启动类
/**
* 启动类
* @author HW
*/
@MapperScan({"com.example.mapper"})
@SpringBootApplication
public class DynamicDataSourceApplication {
public static void main(String[] args) {
SpringApplication.run(DynamicDataSourceApplication.class,args);
}
}
3、案例测试
请求:http://localhost:8082/product/buyProduct?productType=electronicsProductService
结果:
请求:http://localhost:8082/product/buyProduct?productType=fruitsProductService
结果: