策略模式是我们老生常谈的设计模式,也是最经常用到的一种设计模式,主要通过在策略上下文提供接口类型的策略成员变量,传入不同的实现策略来实现不同的业务,主要实现如下
实现方式:
a) 提供公共接口或抽象类,定义需要使用的策略方法。(策略抽象类)
b) 多个实现的策略抽象类的实现类。(策略实现类)
c) 环境类(也叫策略上下文),提供接口类型的成员变量,传入了策略抽象类型的策略实现类。
d) 客户端 调用环境类 进行不同策略的切换。
下面代码是一个简单的策略模式实现,策略接口中有一个计算的方法(doOperator),策略实现类实现了不同的计算方法,通过给策略上下文中传入不同的接口实现类(通过构造方法传入),然后策略上下文中的执行方法(executeStrategy)调用传入的策略实现类中的doOperator方法,客户端调用的时候只需要调用策略上下文提供的executeStrategy即可实现不同的计算,代码如下。
package com.example.learn.utils.shejimoshi.strategy;
public interface Strategy {
public int doOperation(int num1, int num2);
}
class AddOperation implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
class SubOperation implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
class MulOperation implements Strategy {
@Override public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
//创建一个使用了某种策略的类Context,也叫策略上下文
//策略模式避免使用多重条件判断,扩展性良好。不过随着策略类增多,会出现策略类膨胀的问题,而且所有策略类都需要对外暴露。
//以前端到端短任务处理就是用的是策略模式
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
//测试类
class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new AddOperation());
System.out.println("6 + 5 = " + context.executeStrategy(6, 5));
context = new Context(new SubOperation());
System.out.println("6 - 5 = " + context.executeStrategy(6, 5));
context = new Context(new MulOperation());
System.out.println("6 * 5 = " + context.executeStrategy(6, 5));
}
}
这是JDK中的经典设计模式,但是随着后来框架层出不穷的出现,实际项目中已经很少使用这样的策略模式了,都是通过框架来进行,比如之前的一个项目中就用到了,有一个功能就是根据不同的情况分别调用公有云环境接口和私有云环境拉取语音数据和文本数据,将私有云和公有云的不同业务逻辑放在service中来处理的,serivce接口中定义了一个抽象方法,
import com.example.learn.pojo.UserBean;
import org.springframework.stereotype.Service;
@Service
public interface UserService {
UserBean findByName(String name);
}
有两个实现类,分别是公有云环境和私有云环境的实现,
@Service
public class UserviceImpl1 implements UserService {
@Autowired(required=true)
private UserMapper userMapper;
@Override
public UserBean findByName(String name) {
System.out.println("这是第一个实现类");
// 查询用户是否存在,如果用户存在,则通过id查询角色,权限
UserBean bean = userMapper.findByName(name);
if (bean != null) {
// 查询用户信息、角色、权限
bean = userMapper.findById(bean.getId());
}
return bean;
}
@Service
public class UserServiceImpl2 implements UserService {
@Override
public UserBean findByName(String name) {
System.out.println("这是第二个实现类");
return null;
}
然后在controller中通过属性注入的方式注入了service接口类型,
@Controller
public class UserController {
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String passworld;
@Autowired
private UserService userService;
@RequestMapping("/getUser")
public CommonResult<UserBean> getUser(HttpServletRequest reqest, HttpServletResponse response){
CommonResult commonResult = new CommonResult();
UserBean userBean = userService.findByName("xxx");
commonResult.setData(userBean);
return commonResult;
}
然后在xml中配置bean,根据不同环境配置不同UserService的实现类
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
#if(${userServiceKey=="public"}
<bean id="userservice" class="com.example.learn.service.impl.UserviceImpl1"></bean>
#else
<bean id="userservice" class="com.example.learn.service.impl.UserServiceImpl2"></bean>
</beans>
最后在properties中配置userServiceKey=public或者private,这样就能注入不同的接口实现了。
总结:上面主要介绍了实际应用中结合框架来使用的策略模式,已经不单纯是JDK的策略模式了。
UserService就等同于策略抽象类,
UserServiceImpl1和UserServiceImpl2就是策略实现类,
controller就是策略上下文,
xml中配置就是注入策略上下文实现,
前端客户端调用的时候调用controller中的getUser方法,getUser方法调用具体的策略实现类方法。