问题的提出

阅读别人代码的时候最讨厌遇到的就是大段大段的if-else分支语句,一般来说读到下面的时候就忘了上面在判断什么了。很多资料上都会讲到使用策略模式来改进这种代码逻辑。

策略模式的类图如下:

只需要按照这个图写代码就可以了。

策略模式代码的实现

借助Spring框架我们能够轻松的实现策略模式。

举一个简单的例子,我们去咖啡店买咖啡的时候,会根据自己的喜好和胃容量选择大小杯。那么我们就要实现一个CoffeeStategy:

package com.example.demo.strategy;

public interface CoffeeStrategy {
void offer();
}

接下来就是各种具体策略的实现了,以中杯咖啡为例:

package com.example.demo.strategy;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; @Component("MID")
@Slf4j
public class MidCoffee implements CoffeeStrategy {
@Override
public void offer() {
log.info("你的中杯咖啡");
}
}

用Component注解给这个类起一个名字叫做MID,这个在后面的应用上下文中有起效。现在就开始定义应用上下文类:

package com.example.demo.strategy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import java.util.Map; @Service
public class CoffeeContext {
@Autowired
private Map<String, CoffeeStrategy> coffeeStrategyMap; public void getCoffee(String size) {
this.coffeeStrategyMap.get(size).offer();
}
}

因为是使用了Spring框架,所有的Bean都被Spring自行管理,启动之后,Map中会有两个元素:{"MID":MidCoffee}和{"LARGE":LargeCoffee}。在具体的业务逻辑中,只需要引入应用上下文类,每次使用getCoffee方法就可以了。

比如这个Controller方法:

@GetMapping("/get")
public void getCoffee(@Param("size") String size) {
this.coffeeContext.getCoffee(size);
}

请求这个接口,我们能在后台看到具体的日志内容:

2021-09-30 22:46:32.550  INFO 15628 --- [nio-8099-exec-1] com.example.demo.strategy.LargeCoffee    : 您的大杯咖啡
2021-09-30 22:46:39.201 INFO 15628 --- [nio-8099-exec-7] com.example.demo.strategy.LargeCoffee : 您的大杯咖啡

进一步的思考

之前写过Component中起的名字有奇效。如果我们没有用Spring框架去实现策略模式,那么我们的代码要如何编写呢?

首先可以肯定的是策略接口和策略实现类是不需要变的。需要变的地方就是应用上下文了,因为不存在自动注入了。这段代码就会变成大致这样:

package com.example.demo.strategy;

public class CoffeeContext {

    CoffeeStrategy coffeeStrategy;
public CoffeeContext(CoffeeStrategy coffeeStrategy) {
this.coffeeStrategy = coffeeStrategy;
} public void getCoffee() {
this.coffeeStrategy.offer();
}
}

这样,在实际使用的时候,我需要先新建一个具体的实现类对象,然后将这个对象传入策略应用上下文去。这种方式怎么看着都没有Spring的实现方式优雅。

CoffeeStrategy mid = new MidCoffee();
CoffeeContext context = new CoffeeContext(mid);
context.getCoffee();

在我实际改造代码的过程中我发现有些策略其实是一样的,只是个别参数不同罢了。我对接的是各个业务供应商,有些供应商的接口逻辑式样的,只是URL和USERNAME不一样罢了。于是好几个策略实现类的代码重复很严重,这个时候我使用了Java8开始提供的接口default方法。这种方法的好处就是能将这种一样的逻辑提取到interface中,只要实现类不重写,那么就会默认使用default方法。

这样改造之后,我的代码又精简了很多。

心得体会

在我接手现在这个项目代码的时候,之前的程序员将代码写的很直白,就是可以不用任何的设计,直接写逻辑。这也没错,可是用IDEA的时候会各种提示重复代码啊之类的,让人看着不开心。而且还有大量的if-else分支让人摸不着头脑。

在我大刀阔斧的改造之后,代码行数越来越少,但是可读性却越来越高。

此时我是比较理解GoF在设计模式这本书里提到的一句话,大致意思就是开发一个面向对象的程序并不简单。

用SpringBoot实现策略模式的更多相关文章

  1. SpringBoot结合策略模式实战套路

    1. SpringBoot结合策略模式实战套路 1.1. 前言 我们都知道设计模式好,可以让我们的代码更具可读性,扩展性,易于维护,但大部分程序猿一开始都学过至少一遍设计模式吧,实战中不知用到了几成. ...

  2. ## springboot 下策略模式的简单使用

    1.灵魂三问 接手前人(已跑路)项目快乐否? 前人项目不写注释懵逼否? 一个方法中一堆if/else,且业务判断条件用简单数字(或英文字母),不带注释,想打人否?     所以,对于上述三个问题,我写 ...

  3. springboot使用策略模式实现一个基本的促销

    策略模式 定义了算法族,分别封装起来,让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户 源码:https://github.com/youxiu326/sb_promotion.git ...

  4. SpringBoot使用策略模式+工厂模式

    为了防止大量的if...else...或switch case代码的出现,可以使用策略模式+工厂模式进行优化. 在我的项目当中,报表繁多,所以尝试了这种方式进行优化报表的架构.代码很简单,如下: Fa ...

  5. Springboot中实现策略模式+工厂模式

    策略模式和工厂模式相信大家都比较熟悉,但是大家有没有在springboot中实现策略和工厂模式? 具体策略模式和工厂模式的UML我就不给出来了,使用这个这两个模式主要是防止程序中出现大量的IF ELS ...

  6. SpringBoot自定义初始化Bean+HashMap优化策略模式实践

    策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 传统的策略模式一般是创建公共接口.定义公共方法-->然后创建实体类实现公共接口.根据各自的 ...

  7. springboot项目中使用设计模式一策略模式

    策略模式: 使用常用,支付,之前做了微信支付,支付宝支付,然后另外一个同事写了一个银联支付,那么如果代码方法一起就会导致代码不是很好操作所以,采用策略模式进行,同事只需要写一个实现类,就可以了, 在协 ...

  8. 基于Springboot注解的策略模式

    释义 策略模式和多态很相似 可以理解为定义了一个统一的接口,有许多不同的实现类,可以自由选择不同的实时类去执行. 实现 上代码: 定义一个统一的接口: [JavaScript] 纯文本查看 复制代码 ...

  9. 在商城系统中使用设计模式----策略模式之在spring中使用策略模式

    1.前言: 这是策略模式在spring中的使用,对策略模式不了解对同学可以移步在商城中简单对使用策略模式. 2.问题: 在策略模式中,我们创建表示各种策略的对象和一个行为,随着策略对象改变而改变的 c ...

随机推荐

  1. mfc HackerTools进程令牌设置为debug权限

    博客园:https://www.cnblogs.com/ndyxb/p/12734717.html 要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作, ...

  2. WPF---控件模板(一)

    一.控件模板概述 控件的外观通过一个ControlTemplate类型的对象确定,该对象指定了组成一个控件的显示的各种视觉元素. 当WPF创建一个控件时,会创建一个控件类(模板父)的实例,然后实例化通 ...

  3. 【java虚拟机】常用的jvm配置参数

    转自:https://www.cnblogs.com/pony1223/p/8661219.html 零.在IDE的后台打印GC日志: 既然学习JVM,阅读GC日志是处理Java虚拟机内存问题的基础技 ...

  4. 深入理解Java类加载器(二):线程上下文类加载器

    摘要: 博文<深入理解Java类加载器(一):Java类加载原理解析>提到的类加载器的双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的类加载器的实现方式.在Java ...

  5. JavaWeb之HttpSession

    时间:2016-11-17 22:33 --HttpSession一.HttpSession概述    1.HttpSession是由JavaWeb提供的,用来进行会话跟踪的类.    2.sessi ...

  6. 一招解决下载或下拉GitHub项目速度太慢的问题

    相信很多朋友都有过这样的体验,就是从Github上下载或clone别人的项目时特别慢,甚至还会出现链接意外终止的情况,那么今天就来给大家分享一个提速的方法,步骤也非常简单,亲测有效! 首先进入你的目标 ...

  7. 检测一个页面所用的时间的js

    window.onload = function () { var loadTime = window.performance.timing.domContentLoadedEventEnd-wind ...

  8. @RequestParam注解的详细介绍

    @RequestParam (org.springframework.web.bind.annotation.RequestParam)用于将指定的请求参数赋值给方法中的形参. 有三个属性: (1)v ...

  9. 【XSS】XSS修炼之独孤九剑

    题目地址 xcao.vip/test 题目作者给出的解题思路 http://xcao.vip/test/xss/XSS修炼之独孤九剑.pdf 独孤九剑-第一式 题目 过滤了等号 =.小括号 (),要求 ...

  10. 性能测试工具JMeter 基础(六)—— 测试元件: 线程组

    线程组的定义: 线程组是测试计划执行的入口,所有的逻辑控制器和取样器都必须在线程组下,其他的元件根据位置的不同作用域是不同的. 线程组是每个线程都是独立运行测试脚本,一个线程组就等于一个用户,通过多个 ...