1.概述
在实际开发中通常遇到根据传入参数不同选择不同的service执行相应的逻辑,例如:商场结账有多种结算模式,会员以会员价结算,内部员工以内部员工价结算,普通客户按原价结算,后端实现就会根据客户身份不同选择不同的结算方式,通常以if…else…方法处理,但如果客户类型较多,计价模式过多那么将会写许多if…else分支,显然代码层面不友好,而且也不利于后期业务扩展和维护,因此我们可以选择策略模式实现。
2.代码继承关系图
我们定义了接口userDao
,它有两个实现分别为userDaoAImpl
和userDaoBImpl
,我们根据传入类型不同进行选择
3.定义userDao
实现userDaoAImpl
和userDaoBImpl
@Service
public class UserDaoAImpl implements UserDao {
@Override
public void query() {
System.out.println("a");
}
}
@Service
public class UserDaoBImpl implements UserDao {
@Override
public void query() {
System.out.println("b");
}
}
4.定义userEnum
定义关系(写死beanName方式)
public enum UserEnum {
//此处定义类型type和name,其中type为传入参数,name为`UserDao`实现类名字
A("a","userDaoAImpl"),
B("b","userDaoBImpl");
private String type;
private String name;
UserEnum(String type,String name) {
this.type = type;
this.name = name;
}
public String getName(){
return this.name;
}
//根据类型获取枚举
public static UserEnum getByType(String type) {
if (!StringUtils.isEmpty(type)) {
for (UserEnum userEnum : UserEnum.values()) {
if (Objects.equals(type, UserEnum.type)) {
return userEnum;
}
}
}
return null;
}
}
5.定义userService
根据传入类型选择具体实现
@Service
public class UserService {
@Autowired
private Map<String ,UserDao> map;
public void us(String type){
UserEnum userEnum = UserEnum.getByType(type);
String name = UserEnum.getName();
map.get(name).query();
}
}
注意:通过private Map<String,UserDao> map
spring容器会将userDao实现放入该集合中,key对应userName,value对应具体实现
6.调用服务
public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext act = new AnnotationConfigApplicationContext(AppConfig.class);
UserService service = (UserService) act.getBean("userService");
service.us("b");
}
}
结果输出userDaoBImpl
中query打印输出,同理传入"a"则打印userDaoAImpl
中打印
7.通过ApplicationContextAware
实现
上述实现存在一定问题,枚举中写死实现类类名,如果类名变动,则需要修改枚举中定义,在实现开发中也容易忘记,故在此通过spring提供的
ApplicationContextAware
进行实现
-
修改枚举
public enum UserEnum { A("a"), B("b"); private String type; UserEnum(String type) { this.type = type; } public static UserEnum getByType(String type) { if (!StringUtils.isEmpty(type)) { for (UserEnum userDaoEnum : UserEnum.values()) { if (Objects.equals(type, userDaoEnum.type)) { return userDaoEnum; } } } return null; } }
-
修改实现类(增加type定义 )
@Service public class UserDaoAImpl implements UserDao { public UserEnum type() { return UserEnum.A; } @Override public void query() { System.out.println("a"); } } @Service public class UserDaoBImpl implements UserDao { public UserEnum type() { return UserEnum.B; } @Override public void query() { System.out.println("b"); } }
-
修改
userService
实现ApplicationContextAware
@Service public class UserService implements ApplicationContextAware { private Map<UserEnum,UserDao> userDaoMap; public void us(String type){ UserDao userDao = getUserDao(type); userDao.query(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, UserDao> maps = applicationContext.getBeansOfType(UserDao.class); userDaoMap = new HashMap<>(); maps.forEach((key,value)->{ UserEnum type = value.type(); userDaoMap.put(type,value); }); } public UserDao getUserDao(String type){ UserEnum userEnum = UserEnum.getByType(type); return userDaoMap.get(userEnum); } }
- 实现
applicationContextAware
:主要通过applicationContext.getBeansOfType()
获取所有的userDao
实现 - 循环
maps
:替换map
中key
值,将原来的key
->userName
替换为key
->userEnum
- 根据
type
:获取userEnum
,在根据userEnum
获取userDao
实现,故以后即使修改userDao
实现也无需修改userEnum
中定义
1.此种方式较第一种方式灵活,但代码量多一些,两种方式均适用,大家可以根据自己需要选择
2.spring整合策略模式非常方便,同时也可加上模板模式,对于某些固定功能处理起来更加方便 - 实现