前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >策略模式解决多重if-else

策略模式解决多重if-else

作者头像
全栈程序员站长
发布2021-07-14 10:55:49
5890
发布2021-07-14 10:55:49
举报
文章被收录于专栏:全栈程序员必看

使用策略模式解决多重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)?*定义了一组算法,将每个算法都封装起来 [可以理解是类的行为(方法)]

代码语言:javascript
复制
* - 多个类只有算法或行为上稍有不同的场景
 * - 算法需要自由切换的场景
 * - 需要屏蔽算法规则的场景
* 使用场景:
 * 1.出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略
 * 2.商场促销方式,打折、满减等
 * 3.Java AWT中的LayoutManager,即布局管理器
*
* 注意:如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题

2.演示代码

场景: 物流行业中,通常会涉及到EDI报文(XML格式文件)传输和回执接收,每发送一份EDI报文, 后续都会收到与之关联的回执(标识该数据在第三方系统中的流转状态)。 这里枚举几种回执类型:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999, 系统在收到不同的回执报文后,会执行对应的业务逻辑处理。 当然,实际业务场景并没有那么笼统,这里以回执处理为演示案例

2.1.准备实体类对象

代码语言:javascript
复制
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/** * 收据 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Receipt {
   

    /** * 收据信息 */
    private String message;

    /** * 收据类型 */
    private String type;

}
代码语言:javascript
复制
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 创建策略模式和对应的算法

可以通过抽象类或者接口的形式,如果是抽象类。行为适用抽象方法。通过继承让子类去实现抽象方法。如果接口,那就和平时开发一样了呀。

代码语言:javascript
复制
/** * 回执处理策略接口 */
public interface IReceiptHandleStrategy {
   

    void handleReceipt(Receipt receipt);

}
/* * * 策略模式(Strategy),定义了一组算法,将每个算法都封装起来 [可以理解是对类的行为(方法)] * * - 多个类只有算法或行为上稍有不同的场景 * - 算法需要自由切换的场景 * - 需要屏蔽算法规则的场景 * 使用场景: * 1.出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略 * 2.商场促销方式,打折、满减等 * 3.Java AWT中的LayoutManager,即布局管理器 * *注意:如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题 * */
代码语言:javascript
复制
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 封装上下文对象

代码语言:javascript
复制
/** * @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 创建策略工厂生产对应的子类对象

代码语言:javascript
复制
/** * @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 如何使用?

代码语言:javascript
复制
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 反射工具类

代码语言:javascript
复制
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.cn/100731.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用策略模式解决多重if-else
    • 1 策略模式的理解
      • 2.演示代码
        • 2.1.准备实体类对象
        • 2.2 创建策略模式和对应的算法
        • 2.3 封装上下文对象
        • 2.4 创建策略工厂生产对应的子类对象
        • 2.5 如何使用?
        • 2.6 反射工具类
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档