在生活中我们经常遇到这样的场景,当我们在购物时,进场需要仅限在线支付,我们可以选择微信、支付宝等等支付方式,策略模式就是应用在这些场景,虽然我们选择了不同的方式,当时我们达到了相同的目的,那就只能付款。因此,策略模式的核心就是一组可以相互替换的算法。
策略模式会实现同一个接口,或者继承通过抽象类,当我们使用是,能够根据用户的选择实现自动替换
具体的代码实现如下
首先,我们定义一个顶层的接口Calculate
/** * @author haidechizi */public interface Calculate { /** * 计算 * @param x * @param y * @param operate * @return */ int calculate(int x, int y, String operate);}然后再定义具体的实现类
/** * @author haidechizi */public class AddCalculate implements Calculate { /** * 计算 * * @param x * @param y * @param operate * @return */ @Override public int calculate(int x, int y, String operate) { return x + y; }}/** * @author haidechizi */public class SubtractCalculate implements Calculate { /** * 计算 * * @param x * @param y * @param operate * @return */ @Override public int calculate(int x, int y, String operate) { return x - y; }}/** * @author haidechizi */public class MultiplyCalculate implements Calculate { /** * 计算 * * @param x * @param y * @param operate * @return */ @Override public int calculate(int x, int y, String operate) { return x * y; }}然后我们再定义一个类,用于选择具体的策略CalculateFactory
/** * @author haidechizi */public class CalculateFactory { /** * 获取具体的计算方式 * * @param operate * @return */ public static Calculate getInstance(String operate) { if ("+".equals(operate)) { return new AddCalculate(); } else if ("-".equals(operate)) { return new SubtractCalculate(); } else if ("*".equals(operate)) { return new MultiplyCalculate(); } throw new UnsupportedOperationException("不支持当前操作"); }}/** * @author haidechizi */public class Calculator { public static int calculate(int x, int y, String operate) { Calculate calculate = CalculateFactory.getInstance(operate); return calculate.calculate(x, y, operate); } public static void main(String[] args) { int calculate = Calculator.calculate(1, 2, "+"); System.out.println(calculate); calculate = Calculator.calculate(1, 2, "*"); System.out.println(calculate); }}通过上面的代码,我们可以看到,只要我们传递相应的策略标识,程序就会自动为我们选择相应的策略,实现无缝的替换,同时如果需要增加其他策略,我们只需直线接口就行。
策略模式就是一组算法族,他可以完美的替换掉我们代码中的if/else,同时符合开闭原则,易于扩展
策略模式会在代码中增加大量的类,同时用户必须知道所有的策略,才可以实现自由的选择
在工作中,我们有一种解析条码的业务场景,对于不同的商家,条码的解析规则不同,因此,我们需要实现一组算法,来解析条码
/** * @author haidechizi */@Data@AllArgsConstructor@NoArgsConstructorpublic class BarCode { /** * 条码类型 */ private Integer type; /** * 商品编码 */ private String code; /** * 价格 */ private Integer price;}/** * @author haidechizi */public interface BarCodeAnalysis { /** * 解析条码 * * @param itemCode * @return */ BarCode analysis(String itemCode);}/** * @author haidechizi */public class DefaultBarCodeAnalysis implements BarCodeAnalysis { /** * 解析条码 * * @param itemCode * @return */ @Override public BarCode analysis(String itemCode) { String type = itemCode.substring(0, 1); String code = itemCode.substring(1, 6); String price = itemCode.substring(6, 10); return new BarCode(Integer.parseInt(type), code, Integer.parseInt(price)); }}/** * @author haidechizi */public class SpecialBarCodeAnalysis implements BarCodeAnalysis { /** * 解析条码 * * @param itemCode * @return */ @Override public BarCode analysis(String itemCode) { String type = itemCode.substring(0, 1); String code = itemCode.substring(1, 7); String price = itemCode.substring(7, 10); return new BarCode(Integer.parseInt(type), code, Integer.parseInt(price)); }}/** * @author haidechizi */public class BarCodeFactory { public static BarCodeAnalysis getAnalysis(Long vendorId) { if (1 == vendorId) { return new SpecialBarCodeAnalysis(); } return new DefaultBarCodeAnalysis(); }}/** * @author haidechizi */public class AnalysisHelper { public static BarCode analysis(Long vendorId, String itemCode) { BarCodeAnalysis analysis = BarCodeFactory.getAnalysis(vendorId); return analysis.analysis(itemCode); } public static void main(String[] args) { BarCode barCode = analysis(1L, "5478654214"); System.out.println(barCode); }}通过这个实际的案例,我们可以更好的在工作中使用策略模式。
通过上面的两个案例,我们可以发现,在使用的过程中,虽然我们能够很好的增加不同的策略,但是,我们依旧还要修改获取策略的工厂,这显然不能做到不修改之前的代码,那么,我们能够完全不修改代码,使其完全负责开闭原则,满足这一点缺憾呢。
显然是可以做到的,目前Spring使用的最后广泛,相信使用Spring实现,大部分人都能够用得上。
/** * @author haidechizi */@Data@AllArgsConstructor@NoArgsConstructorpublic class BarCode { /** * 条码类型 */ private Integer type; /** * 商品编码 */ private String code; /** * 价格 */ private Integer price;}/** * @author haidechizi */public interface BarCodeAnalysis { /** * 解析条码 * * @param itemCode * @return */ BarCode analysis(String itemCode);}/** * @author dejun.wang * @date 2021/11/25 */public abstract class AbstractBarCodeAnalysis implements BarCodeAnalysis { @PostConstruct public void init() { } protected abstract String type();}/** * @author haidechizi */@Lazy(value = false)@Componentpublic class DefaultBarCodeAnalysis extends AbstractBarCodeAnalysis { /** * 解析条码 * * @param itemCode * @return */ @Override public BarCode analysis(String itemCode) { String type = itemCode.substring(0, 1); String code = itemCode.substring(1, 6); String price = itemCode.substring(6, 10); return new BarCode(Integer.parseInt(type), code, Integer.parseInt(price)); } @Override protected String type() { return "default"; }}/** * @author haidechizi */@Lazy(value = false)@Componentpublic class SpecialBarCodeAnalysis extends AbstractBarCodeAnalysis { /** * 解析条码 * * @param itemCode * @return */ @Override public BarCode analysis(String itemCode) { String type = itemCode.substring(0, 1); String code = itemCode.substring(1, 7); String price = itemCode.substring(7, 10); return new BarCode(Integer.parseInt(type), code, Integer.parseInt(price)); } @Override protected String type() { return "special"; }}/** * @author haidechizi */public class BarCodeFactory { private static final Map analysisHolder = new ConcurrentHashMap<>(); public static void addAnalysis(String type, BarCodeAnalysis barCodeAnalysis) { analysisHolder.put(type, barCodeAnalysis); } public static BarCodeAnalysis getAnalysis(String type) { return Optional.ofNullable(analysisHolder.get(type)).orElse(analysisHolder.get("default")); }} /** * @author haidechizi */public class AnalysisHelper { public static BarCode analysis(Long vendorId, String itemCode) { // 通过数据库获取商家对于的条码解析规则 String type = "default"; BarCodeAnalysis analysis = BarCodeFactory.getAnalysis(type); return analysis.analysis(itemCode); } public static void main(String[] args) { BarCode barCode = analysis(1L, "5478654214"); System.out.println(barCode); }}在Spring中,@PostConstruct在bean初始化时,会进行调用,通过这种方式,我们可以将type和bean的映射关系保存起来,然后直通通过类型去获取相应的bean,这样,我们便可以不用在增加策略类的时候,修改原有的代码,完美的符合了开闭原则。
当然,在Spring中,还有其他方式实现这个功能
/** * @author haidechizi */@Componentpublic class BarCodeFactory2 { private static final Map analysisHolder = new ConcurrentHashMap<>(); @Autowired public void init(List barCodeAnalysisList) { barCodeAnalysisList.forEach(barCodeAnalysis -> { analysisHolder.put(barCodeAnalysis.type(), barCodeAnalysis); }); } public static BarCodeAnalysis getAnalysis(String type) { return Optional.ofNullable(analysisHolder.get(type)).orElse(analysisHolder.get("default")); }} 通过@Autowired注入的方式,我们也可以映射类型和对应的条码的解析之前的关系
| 留言与评论(共有 0 条评论) “” |