做网站收入太低,网站平台选择,vps主机怎么建设网站,搜图片找原图前言
策略模式是平时Java开发中常用的一种#xff0c;虽然已有很多讲解设计模式的文章#xff0c;但是这里还是写篇文章来从自己理解的角度讲解一下。
使用场景
我们不妨进行场景假设#xff0c;要对我们的软件进行授权管理#xff1a;在启动我们的软件之前先要校验是否…前言
策略模式是平时Java开发中常用的一种虽然已有很多讲解设计模式的文章但是这里还是写篇文章来从自己理解的角度讲解一下。
使用场景
我们不妨进行场景假设要对我们的软件进行授权管理在启动我们的软件之前先要校验是否存在合法的授权如果授权不合法则要求用户进行激活操作。作为例子我们就简单地实现一下授权校验功能分发的授权文件中内容是一个四位随机数并且最后一位是数字且为0。我们只要校验授权文件中内容的最后一位是数字0即可。
public class LicenseService {public boolean checkLicense() {boolean result false;// abc0File file Path.of(./secret).toFile();String content ;try{// 读取文件内容BufferedReader br new BufferedReader(new FileReader(file));content br.readLine();br.close();}catch(Exception e){e.printStackTrace();}// 末尾字符是0即认为校验通过if (content.endsWith(0)) {result true;}return result;}
}需求变更
现在需求进行了变更不再校验末尾字符为0了而是校验开头字符是0因此我们需要对程序进行修改。并且我们在调整程序的过程中将读取文件内容和授权校验的逻辑进行分离将授权校验的逻辑抽到一个单独的方法中。
public boolean checkLicense() {...result checkInternal(content, result);...}private static boolean checkInternal(String content, boolean result) {if (content.startsWith(0)) {result true;}return result;}改完之后又接到了最新通知还有可能改回原来末尾字符的判断方式于是我们又对方法进行了调整。通过方法传入一个参数来决定使用哪种方式判断
public boolean checkLicense() {...result checkInternal(content, result, 1);...}private static boolean checkInternal(String content, boolean result, int choose) {// 通过方法传入的choose来决定使用哪种算法if (choose 0) {if (content.endsWith(0)) {result true;}} else if (choose 1) {if (content.startsWith(0)) {result true;}}return result;}策略模式
上面我们的例子是比较简单的但是达到了演示的效果校验授权的实现可能有多个版本并且不同版本的实现都有可能被使用。为了后续方便扩展和维护我们把checkInternal方法中的两个if判断中的逻辑再抽离出来。
首先定义一个策略接口
public interface CheckStrategy {boolean check(String content);
}然后将两个if中的逻辑转到接口的实现类中
public class CheckStart implements CheckStrategy {Overridepublic boolean check(String content) {boolean result false;if (content.startsWith(0)) {result true;}return result;}
}public class CheckEnd implements CheckStrategy {Overridepublic boolean check(String content) {boolean result false;if (content.endsWith(0)) {result true;}return result;}
}接下来再调整一下LicenseService中方法的调用把原来的checkInternal方法中的if语句进行调整改为调用CheckStrategy中的方法
public boolean checkLicense() {...result checkInternal(content, new CheckStart());...
}private static boolean checkInternal(String content, CheckStrategy strategy) {return strategy.check(content);
}更多思考
有说一种对于策略的说法是替换满屏的if else我认为这不能算是策略模式的使用目的只能算是应用了策略模式后的副产物。
它更多的使用场景是这样有某一大方法其中的一个环节可以有不同实现并且进行环节的算法替换时不影响原大方法的功能或受到预期的控制。这里再举一些应用场景的例子不够精准但重在体会其中的思想
实现游戏可以用不同的底层引擎引擎之间的替换可以应用策略模式程序和数据库交互时可能用到不同的数据库产品如mysql、sqllite对不同数据库的交互操作可以应用策略模式别的我暂时想不起来了
Spring中实战
现在java web应用里Spring算是事实上的标准了在Spring中用策略模式还是有一些小技巧的。下面直接给出代码请同学们品。
Service
public class LicenseService {// 注入strategy managerAutowiredprivate StrategyManager strategyManager;public boolean checkLicense() {boolean result false;// abc0File file Path.of(./secret).toFile();String content ;try {// 读取文件内容BufferedReader br new BufferedReader(new FileReader(file));content br.readLine();br.close();} catch (Exception e) {e.printStackTrace();}// 由manager作为策略类实现的提供者result strategyManager.pickCheckStrategy(CheckStrategyEnum.START.toString()).check(content);return result;}
}Service
public class StrategyManager {// 注入CheckStrategy listAutowiredprivate ListCheckStrategy checkStrategyList;public CheckStrategy pickCheckStrategy(String type) {// 根据传入的type从上面list中取出对应的策略实现类并返回给调用者return checkStrategyList.stream().filter(s - s.type().equals(type)).findFirst().orElseThrow();}
}enum CheckStrategyEnum {END, START;
}public interface CheckStrategy {/*** 返回策略实现类的类型用于为manager提供实现类的标识** return 自定义的枚举类型 {link CheckStrategyEnum}*/String type();/*** 判断授权。算法由实现类确定** param content 判断的内容* return 是否判断成功*/boolean check(String content);
}Service
public class CheckStart implements CheckStrategy {Overridepublic String type() {// 返回对应的枚举typereturn CheckStrategyEnum.END.toString();}Overridepublic boolean check(String content) {boolean result false;if (content.startsWith(0)) {result true;}return result;}
}Service
public class CheckEnd implements CheckStrategy {Overridepublic String type() {// 返回对应的枚举typereturn CheckStrategyEnum.START.toString();}Overridepublic boolean check(String content) {boolean result false;if (content.endsWith(0)) {result true;}return result;}
}