策略模式解决多重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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

发表回复

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

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