使用策略模式解决多重if-else
参考学习资料:
- https://www.cnblogs.com/adamjwh/p/11011095.html
- https://mp.weixin.qq.com/s/P0G8YHY3kQHJ90NyrOrmOA
最近现在项目开发中遇到公众号发送模板消息。项目经理申请了很多种模板发送消息给关注着。如果不使用设计模式需要使用switch 或者if-else 造成 代码臃肿。看到一篇使用策略模式+工厂+字典map 解决多重if-else 。分享给大家。相互学习。有什么不对的请指正。谢谢.
1 策略模式的理解
**策略模式(Strategy)?*定义了一组算法,将每个算法都封装起来 [可以理解是类的行为(方法)]
* - 多个类只有算法或行为上稍有不同的场景
* - 算法需要自由切换的场景
* - 需要屏蔽算法规则的场景
* 使用场景:
* 1.出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略
* 2.商场促销方式,打折、满减等
* 3.Java AWT中的LayoutManager,即布局管理器
*
* 注意:如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题
2.演示代码
场景:
物流行业中,通常会涉及到EDI报文(XML格式文件)传输和回执接收,每发送一份EDI报文,
后续都会收到与之关联的回执(标识该数据在第三方系统中的流转状态)。
这里枚举几种回执类型:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999,
系统在收到不同的回执报文后,会执行对应的业务逻辑处理。
当然,实际业务场景并没有那么笼统,这里以回执处理为演示案例
2.1.准备实体类对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/** * 收据 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Receipt {
/** * 收据信息 */
private String message;
/** * 收据类型 */
private String type;
}
import java.util.ArrayList;
import java.util.List;
/** * 构造Receipt收据实体类对象. 在实际项目中,这些数据前端传递参数封装对应的对象的。 */
public class ReceiptBuilder {
public static List<Receipt> generateReceiptList(){
//直接模拟一堆回执对象
List<Receipt> receiptList = new ArrayList<>();
receiptList.add(new Receipt("我是MT2101回执喔","MT2101"));
receiptList.add(new Receipt("我是MT1101回执喔","MT1101"));
receiptList.add(new Receipt("我是MT8104回执喔","MT8104"));
receiptList.add(new Receipt("我是MT9999回执喔","MT9999"));
//......
return receiptList;
}
}
2.2 创建策略模式和对应的算法
可以通过抽象类或者接口的形式,如果是抽象类。行为适用抽象方法。通过继承让子类去实现抽象方法。如果接口,那就和平时开发一样了呀。
/** * 回执处理策略接口 */
public interface IReceiptHandleStrategy {
void handleReceipt(Receipt receipt);
}
/* * * 策略模式(Strategy),定义了一组算法,将每个算法都封装起来 [可以理解是对类的行为(方法)] * * - 多个类只有算法或行为上稍有不同的场景 * - 算法需要自由切换的场景 * - 需要屏蔽算法规则的场景 * 使用场景: * 1.出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略 * 2.商场促销方式,打折、满减等 * 3.Java AWT中的LayoutManager,即布局管理器 * *注意:如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题 * */
public class Mt1101ReceiptHandleStrategy implements IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT1101:" + receipt.getMessage());
}
}
public class Mt2101ReceiptHandleStrategy implements IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT2101:" + receipt.getMessage());
}
}
public class Mt8104ReceiptHandleStrategy implements IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT8104:" + receipt.getMessage());
}
}
import com.example.strategydemo.pojo.Receipt;
import com.example.strategydemo.strategy.IReceiptHandleStrategy;
public class Mt9999ReceiptHandleStrategy implements IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT9999:" + receipt.getMessage());
}
}
2.3 封装上下文对象
/** * @Description: 上下文类,持有策略接口 */
public class ReceiptStrategyContext {
// set 方式 ---- 类的关系是聚合的关系.如果直接new 对象的话是组合关系
private IReceiptHandleStrategy receiptHandleStrategy;
/** * 设置策略接口 * @param receiptHandleStrategy */
public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy) {
this.receiptHandleStrategy = receiptHandleStrategy;
}
//上下文对象封装了策略 行为,后面通过工厂创建对应策略对象。然后调用这个方法去做处理,也就是运用到多态的知识。真正做事情的是其子类
public void handleReceipt(Receipt receipt){
if (receiptHandleStrategy != null) {
receiptHandleStrategy.handleReceipt(receipt);
}
}
}
2.4 创建策略工厂生产对应的子类对象
/** * @Description: 策略工厂 * @Auther: wuzhazha */
public class ReceiptHandleStrategyFactory {
private static Map<String, IReceiptHandleStrategy> receiptHandleStrategyMap;
private ReceiptHandleStrategyFactory(){
this.receiptHandleStrategyMap = new HashMap<>();
this.receiptHandleStrategyMap.put("MT2101",new Mt2101ReceiptHandleStrategy());
this.receiptHandleStrategyMap.put("MT8104",new Mt8104ReceiptHandleStrategy());
}
public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){
return receiptHandleStrategyMap.get(receiptType);
}
}
2.5 如何使用?
public class Client {
public static void main(String[] args) {
//模拟回执
List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();
//策略上下文
ReceiptStrategyContext receiptStrategyContext = new ReceiptStrategyContext();
for (Receipt receipt : receiptList) {
//通过收据类型 在工厂中获取对应的 策略对象 对象 [运用了多态]----工厂
IReceiptHandleStrategy receiptHandleStrategy = ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());
//拿到策略对象 设置给策略上下文
receiptStrategyContext.setReceiptHandleStrategy(receiptHandleStrategy);
//上下文对象封装了 执行策略的公共方法 [ 向上抽取一种思想]
//Context上下文角色,也叫Context封装角色,起承上启下的作用,
// 屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
//【简单来说运用了封装 、多态思想】【看来还要继续回炉,重新认识面向对象】
receiptStrategyContext.handleReceipt(receipt);
}
}
}
//后期扩展对工厂进行新增即可,不会影响其他的代码。
//就像作者说的一样使用反射创建对象,那就真正的满足设计原则 :开闭原则了.
2.6 反射工具类
public class ReflectionUtil {
/** * 定义类集合(用于存放所有加载的类) */
private static final Set<Class<?>> CLASS_SET;
static {
//指定加载包路径
CLASS_SET = getClassSet("com.yaolong");
}
/** * 获取类加载器 * @return */
public static ClassLoader getClassLoader(){
return Thread.currentThread().getContextClassLoader();
}
/** * 加载类 * @param className 类全限定名称 * @param isInitialized 是否在加载完成后执行静态代码块 * @return */
public static Class<?> loadClass(String className,boolean isInitialized) {
Class<?> cls;
try {
cls = Class.forName(className,isInitialized,getClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return cls;
}
public static Class<?> loadClass(String className) {
return loadClass(className,true);
}
/** * 获取指定包下所有类 * @param packageName * @return */
public static Set<Class<?>> getClassSet(String packageName) {
Set<Class<?>> classSet = new HashSet<>();
try {
Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".","/"));
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String protocol = url.getProtocol();
if (protocol.equals("file")) {
String packagePath = url.getPath().replace("%20","");
addClass(classSet,packagePath,packageName);
} else if (protocol.equals("jar")) {
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
if (jarURLConnection != null) {
JarFile jarFile = jarURLConnection.getJarFile();
if (jarFile != null) {
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String jarEntryName = jarEntry.getName();
if (jarEntryName.endsWith(".class")) {
String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
doAddClass(classSet,className);
}
}
}
}
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return classSet;
}
private static void doAddClass(Set<Class<?>> classSet, String className) {
Class<?> cls = loadClass(className,false);
classSet.add(cls);
}
private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {
final File[] files = new File(packagePath).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
}
});
for (File file : files) {
String fileName = file.getName();
if (file.isFile()) {
String className = fileName.substring(0, fileName.lastIndexOf("."));
if (StringUtils.isNotEmpty(packageName)) {
className = packageName + "." + className;
}
doAddClass(classSet,className);
} else {
String subPackagePath = fileName;
if (StringUtils.isNotEmpty(packagePath)) {
subPackagePath = packagePath + "/" + subPackagePath;
}
String subPackageName = fileName;
if (StringUtils.isNotEmpty(packageName)) {
subPackageName = packageName + "." + subPackageName;
}
addClass(classSet,subPackagePath,subPackageName);
}
}
}
public static Set<Class<?>> getClassSet() {
return CLASS_SET;
}
/** * 获取应用包名下某父类(或接口)的所有子类(或实现类) * @param superClass * @return */
public static Set<Class<?>> getClassSetBySuper(Class<?> superClass) {
Set<Class<?>> classSet = new HashSet<>();
for (Class<?> cls : CLASS_SET) {
if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) {
classSet.add(cls);
}
}
return classSet;
}
/** * 获取应用包名下带有某注解的类 * @param annotationClass * @return */
public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass) {
Set<Class<?>> classSet = new HashSet<>();
for (Class<?> cls : CLASS_SET) {
if (cls.isAnnotationPresent(annotationClass)) {
classSet.add(cls);
}
}
return classSet;
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100731.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...