策略模式实践
回顾项目中的代码,看到诸多的if-else,心中倍感不适。想起最近了解到的策略模式,于是想到优化下。该方式要结合spring框架,并将一类策略写到同一个包下,所有的策略也均写到一个包下。这样在spring启动时会自动创建策略工厂以及策略的BeanDefinition,在使用策略工厂时会自动将相应的策略注册到策略工厂中。
创建stratgies包
策略接口,规定策略类型,策略执行器
/**
* 策略
* @param <P> 策略执行所需传入的参数类型
* @param <R> 策略执行后的返回值类型
* @param <T> 策略类型
*/
public interface Strategy<P,R,T>{
/**
* 执行策略
* @param p
* @return
*/
R execute(P p);
/**
* 获取策略类型
* @return
*/
T getType();
/**
* 执行策略
* 多参数
* @param params
* @return
*/
default R execute(Object... params) {
return null;
}
}
创建策略工厂。获取策略,初始化工厂bean时注册策略类。
/**
* 策略工厂模板
* @param <T>
*/
public class StrategyFactory<T> implements BeanFactoryAware {
private Map<T,Strategy> strateies;
private BeanFactory beanFactory;
/**
* 获取相应的策略
* @param t
* @return
*/
public Strategy getStrategy(T t){
Strategy strategy=strateies.get(t);
if(strategy==null)
//T为null相当于if-else中最后的else,switch中最后的default。
return strateies.get(null);
return strategy;
}
/**
* 注册相应的策略类到该策略工厂
*/
@PostConstruct
public void initStrateies(){
this.strateies=new HashMap<>();
String path=this.getClass().getName();
path=path.substring(0,path.lastIndexOf("."));
ClassLoader classLoader=this.getClass().getClassLoader();
File[] roots=new File(classLoader.getResource(path.replace(".", "/")).getFile()).listFiles();
for(File root:roots){
if(root.isDirectory())continue;
String classPath=path+"."+root.getName().substring(0,root.getName().lastIndexOf("."));
try {
Class clazz=classLoader.loadClass(classPath);
if(Strategy.class.isAssignableFrom(clazz)){
Strategy strategy= (Strategy) beanFactory.getBean(clazz);
this.strateies.put((T) strategy.getType(),strategy);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory=beanFactory;
}
}
创建StrategyRegistryPostProcessor,用于注册策略工厂,策略的BeanDefinition。可省去策略,策略工厂的 @Componmet 注解。
@Component
public class StrategyRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassLoader classLoader=this.getClass().getClassLoader();
String path=this.getClass().getName();
path=path.substring(0,path.lastIndexOf("."));
File[] roots=new File(classLoader.getResource(path.replace(".", "/")).getFile()).listFiles();
for(File root:roots){
if(root.isFile())continue;
String packege=path+"."+root.getName()+".";
File[] clazzFiles=root.listFiles();
Class clazz=null;
for(File clazzFile:clazzFiles){
if(clazzFile.isFile()){
String classPath=packege+clazzFile.getName().substring(0,clazzFile.getName().indexOf("."));
try {
clazz=classLoader.loadClass(classPath);
boolean isStrategyFactory=StrategyFactory.class.isAssignableFrom(clazz);
if(isStrategyFactory||Strategy.class.isAssignableFrom(clazz)){
char[] beanName=clazz.getSimpleName().toCharArray();
beanName[0]+=32;
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(clazz).getBeanDefinition();
beanDefinition.setLazyInit(isStrategyFactory);
registry.registerBeanDefinition(new String(beanName), beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
使用案例
DemoStrategyFactory
public class DemoStrategyFactory extends StrategyFactory<Integer> {}
Type1Strategy
public class Type1Strategy implements Strategy<String,Integer, Integer> {
@Override
public Integer execute(String s) {
System.out.println("a");
return 1;
}
@Override
public Integer getType() {
return 1;
}
}
Type2Strategy
public class Type2Strategy implements Strategy<String,Integer, Integer> {
@Override
public Integer execute(String s) {
System.out.println("b");
return 2;
}
@Override
public Integer getType() {
return 2;
}
}
Type3Strategy
public class Type3Strategy implements Strategy<String,Integer, Integer> {
@Override
public Integer execute(String s) {
System.out.println("c");
return 3;
}
@Override
public Integer getType() {
//规定返回null为随后的else/default
return null;
}
}
使用
DemoService
@Service
public class DemoService{
@Autowired
private DemoStrategyFactory demoStrategyFactory;
public Integer test(Integer type){
Strategy strategy=demoStragegyFactory.getStrategy(type);
Integer res=(Integer) strategy.execute(null);
return res;
}
}