案例突破——再探策略模式

一、背景介绍

在做项目重构的过程中,发现对于主题讨论中,针对于学生评论/回复的内容的按照评论/回复日期排序、按照评论数量排序、按照点赞次数排序可以使用策略模式进行优化。

二、 思路方案

  1. 策略模式基本概念
  2. 策略模式类图
  3. 策略模式基本代码
  4. 策略模式还可以进行优化的地方
  5. 对策略模式进行优化

三、过程

1. 策略模式基本概念

定义:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化不会影响到使用算法的客户。

2. 策略模式类图

在这里插入图片描述

3. 策略模式基本代码

策略类

package com.wangwei.strategypattern.normal;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : ConcreteStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:34]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:34]
 * @updateRemark : [描述说明本次修改内容]
 */
public class ConcreteStrategyA implements IStrategy{
    public void AlgorithmInterface(){
        System.out.println("算法A实现");
    }
}

package com.wangwei.strategypattern.normal;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : ConcreteStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:34]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:34]
 * @updateRemark : [描述说明本次修改内容]
 */
public class ConcreteStrategyB implements IStrategy{
    public void AlgorithmInterface(){
        System.out.println("算法B实现");
    }
}

package com.wangwei.strategypattern.normal;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : ConcreteStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:34]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:34]
 * @updateRemark : [描述说明本次修改内容]
 */
public class ConcreteStrategyC implements IStrategy{
    public void AlgorithmInterface(){
        System.out.println("算法C实现");
    }
}



抽象策略类

package com.wangwei.strategypattern.normal;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : IStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:37]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:37]
 * @updateRemark : [描述说明本次修改内容]
 */
public interface IStrategy {
    void AlgorithmInterface();
}

Context类

package com.wangwei.strategypattern.normal;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : Context
 * @description : [公共上下文]
 * @createTime : [2023/9/7 10:38]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:38]
 * @updateRemark : [描述说明本次修改内容]
 */
public class Context {
    IStrategy iStrategy=null;

    public Context(IStrategy iStrategy) {
        this.iStrategy = iStrategy;
    }

    public void ContextInterface(){
        iStrategy.AlgorithmInterface();
    }
}

客户端

package com.wangwei.strategypattern.normal;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : Client
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:40]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:40]
 * @updateRemark : [描述说明本次修改内容]
 */
public class Client {
    public static void main(String[] args) {
        Context context=null;

        context= new Context(new ConcreteStrategyA());
        context.ContextInterface();

        context = new Context(new ConcreteStrategyB());
        context.ContextInterface();

        context = new Context(new ConcreteStrategyB());
        context.ContextInterface();
    }
}

4. 策略模式还可以进行优化的地方

当我们需要增加新的策略的时候,是需要修改客户端的代码,那么对于客户端来说是不符合开闭原则的。

5. 对策略模式的优化(配置文件+反射)

package com.wangwei.strategypattern.better;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : ConcreteStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:34]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:34]
 * @updateRemark : [描述说明本次修改内容]
 */
public class ConcreteStrategyA implements IStrategy {
    public void AlgorithmInterface(){
        System.out.println("算法A实现");
    }
}

package com.wangwei.strategypattern.better;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : ConcreteStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:34]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:34]
 * @updateRemark : [描述说明本次修改内容]
 */
public class ConcreteStrategyB implements IStrategy {
    public void AlgorithmInterface(){
        System.out.println("算法B实现");
    }
}

package com.wangwei.strategypattern.better;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : ConcreteStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:34]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:34]
 * @updateRemark : [描述说明本次修改内容]
 */
public class ConcreteStrategyC implements IStrategy {
    public void AlgorithmInterface(){
        System.out.println("算法C实现");
    }
}

package com.wangwei.strategypattern.better;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : Context
 * @description : [公共上下文]
 * @createTime : [2023/9/7 10:38]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:38]
 * @updateRemark : [描述说明本次修改内容]
 */
public class Context {

    static Map<String,String> config = new HashMap<>();
    static Map<String,IStrategy> configBean = new HashMap<>();
    //提前读取配置文件中的策略,并提前准备好已有的策略对象
    static {
        InputStream inputStream = Context.class.getResourceAsStream("/config.properties");
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String strategyType = properties.getProperty("strategyType");
        String[] strs = strategyType.split(",");

        for (String string : strs) {
            String key = string.split(":")[0];
            String value = string.split(":")[1];
            // 去掉头部空格
            String key1 = key.trim();
            String value1 = value.trim();
            config.put(key1, value1);
        }
        //提前准备好已有的策略对象
        for (Map.Entry<String,String> entry:config.entrySet()) {
            Class strategyClass ;
            try {
                strategyClass = Class.forName(entry.getValue());
                configBean.put(entry.getKey(),(IStrategy) strategyClass.getConstructor().newInstance());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }

    }
    IStrategy iStrategy;
    public Context(String type) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
        if(configBean.containsKey(type)){
            this.iStrategy = configBean.get(type);
        }else {
            Class strategyClass = Class.forName(config.get(type));
            this.iStrategy = (IStrategy)strategyClass.getConstructor().newInstance();
        }
    }
    public void ContextInterface(){
        iStrategy.AlgorithmInterface();
    }



}

package com.wangwei.strategypattern.better;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : IStrategy
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:37]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:37]
 * @updateRemark : [描述说明本次修改内容]
 */
public interface IStrategy {
    void AlgorithmInterface();
}

package com.wangwei.strategypattern.better;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : Client
 * @description : [描述说明该类的功能]
 * @createTime : [2023/9/7 10:40]
 * @updateUser : [WangWei]
 * @updateTime : [2023/9/7 10:40]
 * @updateRemark : [描述说明本次修改内容]
 */
public class Client {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException {
        /*
        1.前端通过下拉框选择不同的类型
        2.类型是从配置文件中读取的
         */
        Context context;
        context= new Context("strategyA");
        context.ContextInterface();

        context = new Context("strategyB");
        context.ContextInterface();

        context = new Context("strategyC");
        context.ContextInterface();
    }
}

四、总结

  1. 优点:配置文件+反射的方式,符合开闭原则。用户可以在不修改原有代码的基础上选择算法,也可以灵活的增加新的算法。

  2. 缺点:无法同时在客户端使用多个策略类。

  3. 关键点:都是对通一份数据,根据不同的算法进行处理。

  4. 什么时候使用策略模式:一个系统需要动态地在几种算法中选择一种。

五、升华

  1. 学习是一个反复的过程:通过项目切实的需求来结合具体的设计模式,在反过来在此基础上优化设计模式。