策略模式
2018-05-14 本文已影响0人
jjjjxd
本质:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换,解除使用算法者之间与算法的耦合(当遇到多个if-else或switch使用)
实际使用: 在之前做的一个项目中有将xml转换成HashMap,xml类型有多种,不同种类型xml格式不同,因此有不同的转换方法,如果不用设计模式则必须使用大量if-else来判断xml类型,下面使用策略模式进行改造:
image image image image image问题:在选择策略是也会遇到大量if-else
image在选择策略时,使用 简单工厂模式,可以看到当报文类型更多时,if-else体积也会变得庞大,并且新增策略时就必须修改策略工厂,这与开放封闭-原则也不符,目前我们项目采用的是将策略注入到Spring容器当中,按照beanName查找策略,这种方法比较好想,但是如果策略不能和bean建立一一对应关系,则可以使用自定义注解实现
package com.msgconverter;
import java.io.File;
import java.io.FileFilter;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
/**
* @author jxdong
* @date 2018/5/13
*/
public class MsgFactory {
private static final String CONVERTER_PACKAGE = "com.msgconverter";//策略类所在的包
private static List<Class<? extends MsgConverter>> CONVERTER_LIST;//策略列表
private ClassLoader classLoader = getClass().getClassLoader();//我们加载策略时的类加载器,我们任何类运行时信息必须来自该类加载器
//不允许通过构造函数实例工厂
private MsgFactory() {
init();
}
private void init() {
CONVERTER_LIST = new ArrayList<>();
File[] classFile = getClassFiles();
Class msgConverterClazz = null;
try {
msgConverterClazz = classLoader.loadClass(MsgConverter.class.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException("未找到策略接口");
}
for (File file : classFile) {
try {
//载入包下的类
Class<?> clazz = classLoader.loadClass(CONVERTER_PACKAGE + "." + file.getName().replace(".class", ""));
//判断是否是MsgConverter的实现类并且不是MsgConverter它本身,满足的话加入到策略列表
if (MsgConverter.class.isAssignableFrom(clazz) && clazz != msgConverterClazz) {
CONVERTER_LIST.add((Class<? extends MsgConverter>) clazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public MsgConverter getMsgConverter(String msgType) throws Exception {
//假设类型有Pay Refund两种
for (Class<? extends MsgConverter> clazz : CONVERTER_LIST) {
MsgType msgTypeAnnotation = clazz.getDeclaredAnnotation(MsgType.class);
if (null != msgTypeAnnotation) {
if (msgType.equals(msgTypeAnnotation.msgType())) {
return clazz.newInstance();
}
} else {
throw new Exception("策略获取失败");
}
}
return null;
}
private File[] getClassFiles() {
try {
File file = new File(classLoader.getResource(CONVERTER_PACKAGE.replace(".", "/")).toURI());
return file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(".class")) {//只扫描class文件
return true;
}
return false;
}
});
} catch (URISyntaxException e) {
throw new RuntimeException("未找到策略");
}
}
//单例工厂
public static class MsgFactoryHolder {
private static MsgFactory INSTANCE = new MsgFactory();
public static MsgFactory getInstance() {
return INSTANCE;
}
}
}
在看策略模式的时候看到一个有趣的问题,上面的代码并不能实现多个策略重叠(本例中没有该需求),如果有则进行改造