策略模式解决多重if-else

策略模式解决多重if-else

使用策略模式解决多重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;
    }


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/100731.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vue 重新加载页面_页面重新加载

    vue 重新加载页面_页面重新加载Vue刷新页面重新加载问题描述在加载同一路由页面的时候,vue的页面默认是不刷新的,需要重新加载数据解决方案修改App.vue在路由视图上添加一个变量isRouterAlive判断显示实现重新加载<template><!–<router-view/>–><router-viewv-if=”isRouterAlive”/></template><script>/*这个脚本主要是用来刷新页面的

    2022年10月17日
    0
  • a星算法c++实现_递归算法理解

    a星算法c++实现_递归算法理解翻了翻别人写的博客,我看到一个A星算法,只怪自己见识太少,竟然没听过这个算法。网上查了好些资料,自己对这算法理解了些,并用C#实现出来。           A星算法,也叫A*算法。这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。如在一张dota地图上,英雄从一个地方走动到地图上另一个点,它选择最优路线的算法。       如上图,绿点是

    2022年10月6日
    0
  • vue 高德地图标记_如何在vue里面调用高德地图「建议收藏」

    vue 高德地图标记_如何在vue里面调用高德地图「建议收藏」1.修改webpac.base.conf.js文件与module同一级添加externals:{‘AMap‘:‘AMap‘,‘AMapUI‘:‘AMapUI‘}配置。然后在index页面引入文件接着下载包vue-amap,然后在vue页面中importAMapfrom‘AMap‘//在使用地图的页面引入该组件varmapexportdefault{mounted:functio…

    2022年5月21日
    38
  • mysql批量添加数据sql语句_sql insert into 批量

    mysql批量添加数据sql语句_sql insert into 批量在MySQL数据库中,如果要插入上百万级的记录,用普通的insertinto来操作非常不现实,速度慢人力成本高,推荐使用LoadData或存储过程来导入数据,我总结了一些方法分享如下,主要基于MyISAM和InnoDB引擎。1InnoDB存储引擎首先创建数据表(可选),如果有了略过:1>CREATEDATABASEecommerce;2>USEecommerce;3&…

    2022年10月5日
    0
  • 我们做出了一个艰难的决定

    我们做出了一个艰难的决定经过半年多的考虑和准备,前天晚上,我们做出了一个艰难的决定:让大儿子在家读书。我厌倦了孩子题海战术,买的课外书根本没有时间读,而他的身心健康变得越来越糟糕了。我知道有很多的理由可以让孩子继续读书,譬如

    2022年7月3日
    18
  • Springboot项目搭建(前端到数据库,超详细)

    Springboot项目搭建(前端到数据库,超详细)下面详细谈谈我的第一个springboot项目搭建,希望会给还在摸索的同学一点帮助。项目说明:开发环境:Eclipse4.42框架:Springboot工具:Maven前端:Html、Thymeleaf后台:Hibernate数据库:Mysql为什么要搭建Springboot项目?教科书式的阐述这里就不说了,我就总结为两个词语“简单、方便”。为了更…

    2022年6月16日
    53

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号