项目场景:
提示:这里简述项目相关背景:
示例:商城系统有会员系统,不同会员有不同优惠程度,普通会员不优惠;黄金会员打8折;白金会员优惠50元,再打7折;
问题描述
提示:这里描述项目中遇到的问题:
例如:不同会员处理过程中,业务场景复杂,每种会员的业务逻辑很长,不方便维护。
public static double quote(String type) {
double score = 1000;
double res = 0;
if (type.equals("1")) {
res = score;
} else if (type.equals("2")) {
res = score - 50;
} else if (type.equals("3")) {
res = score * 0.8;
} else if (type.equals("4")) {
res = (score - 50) * 0.7;
}
return res;
}
原因分析:
提示:这里填写问题的分析:
业务复杂
解决方案:
提示:这里填写该问题的具体解决方案:
package com.geekmice.springbootmybatiscrud.strategy.third;
import java.math.BigDecimal;
public interface PayStrategy {
/**
* 计算费用
*
* @param price
* @date 2025-02-10
*/
BigDecimal quote(BigDecimal price);
}
具体策略1:非会员,没有优惠
package com.geekmice.springbootmybatiscrud.strategy.third;
import java.math.BigDecimal;
public class OrdinaryStrategy implements PayStrategy{
@Override
public BigDecimal quote(BigDecimal price) {
return price;
}
}
具体策略2:黄金会员,打八折
package com.geekmice.springbootmybatiscrud.strategy.third;
import java.math.BigDecimal;
import java.util.Objects;
public class GoldStrategy implements PayStrategy{
@Override
public BigDecimal quote(BigDecimal price) {
BigDecimal res = price.multiply(new BigDecimal("0.8"));
return res;
}
}
具体策略3:白银会员,先优惠50,后打七折
package com.geekmice.springbootmybatiscrud.strategy.third;
import com.geekmice.springbootmybatiscrud.strategy.first.Strategy;
import java.math.BigDecimal;
public class PlatinumStrategy implements PayStrategy {
@Override
public BigDecimal quote(BigDecimal price) {
BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));
return res;
}
}
上下文对象:持有一个Strategy的引用
package com.geekmice.springbootmybatiscrud.strategy.third;
import java.math.BigDecimal;
/**
* @author Administrator
*/
public class PayContext {
private PayStrategy payStrategy;
public void setStrategy(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
public BigDecimal getPrice(BigDecimal price) {
if (payStrategy != null) {
return payStrategy.quote(price);
}
return null;
}
}
测试使用
package com.geekmice.springbootmybatiscrud.strategy.third;
import java.math.BigDecimal;
public class Demo {
public static void main(String[] args) {
PayContext payContext = new PayContext();
OrdinaryStrategy ordinaryStrategy = new OrdinaryStrategy();
payContext.setStrategy(ordinaryStrategy);
System.out.println("普通会员:"+payContext.getPrice(new BigDecimal("100")));
GoldStrategy goldStrategy = new GoldStrategy();
payContext.setStrategy(goldStrategy);
System.out.println("黄金会员:"+payContext.getPrice(new BigDecimal("100")));
PlatinumStrategy platinumStrategy = new PlatinumStrategy();
payContext.setStrategy(platinumStrategy);
System.out.println("白银会员:"+payContext.getPrice(new BigDecimal("100")));
}
}
结果
普通会员:100
黄金会员:80.0
白银会员:35.0
优化1:新增其他策略,不影响现有的策略
思路:新增策略类,实现策略接口
package com.geekmice.springbootmybatiscrud.strategy.third;
import java.math.BigDecimal;
public class SilverStrategy implements PayStrategy{
@Override
public BigDecimal quote(BigDecimal price) {
return price.subtract(new BigDecimal("50"));
}
}
package com.geekmice.springbootmybatiscrud.strategy.third;
import java.math.BigDecimal;
public class Demo {
public static void main(String[] args) {
PayContext payContext = new PayContext();
OrdinaryStrategy ordinaryStrategy = new OrdinaryStrategy();
payContext.setStrategy(ordinaryStrategy);
System.out.println("普通会员:"+payContext.getPrice(new BigDecimal("100")));
GoldStrategy goldStrategy = new GoldStrategy();
payContext.setStrategy(goldStrategy);
System.out.println("黄金会员:"+payContext.getPrice(new BigDecimal("100")));
PlatinumStrategy platinumStrategy = new PlatinumStrategy();
payContext.setStrategy(platinumStrategy);
System.out.println("白银会员:"+payContext.getPrice(new BigDecimal("100")));
SilverStrategy silverStrategy = new SilverStrategy();
payContext.setStrategy(silverStrategy);
System.out.println("白金会员:"+payContext.getPrice(new BigDecimal("100")));
}
}
普通会员:100
黄金会员:80.0
白银会员:35.0
白金会员:50
优化2:策略中出现相同逻辑,如何处理
说明:策略2与策略3处理逻辑中都有需要处理的内容,这个内容可能很长,初始化参数,或者校验参数,远程调用获取数据等操作,都是类似的逻辑,可以抽取到抽象类中,子类需要哪个实现哪个方法,重复的直接在父类操作。
策略工厂
package com.geekmice.springbootmybatiscrud.strategy.fifth;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author mbp
* @date 2025-02-11
*/
public class StrategyFactory {
/**
* 设置策略map
*/
private static Map<String, Strategy> strategyMap = new HashMap<>(16);
public static Strategy getStrategyService(String type) {
return strategyMap.get(type);
}
/**
* 提前策略装入 strategyMap
*/
public static void register(String type, Strategy strategy) {
if (Objects.isNull(type)) {
return;
}
strategyMap.put(type, strategy);
}
}
策略接口
package com.geekmice.springbootmybatiscrud.strategy.fifth;
import org.springframework.beans.factory.InitializingBean;
import java.math.BigDecimal;
/**
* @author mbp
* @date 2025-02-11
*/
public interface Strategy extends InitializingBean {
BigDecimal quote(BigDecimal price);
}
模板方式抽象类
package com.geekmice.springbootmybatiscrud.strategy.fifth;
/**
* @author mbp
* @date 2025-02-11
*/
public abstract class BaseMember {
/**
* 需要父类执行关键重复逻辑
*/
protected void exec(){
System.out.println("处理内容");
}
}
具体策略1
package com.geekmice.springbootmybatiscrud.strategy.fifth;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* @author mbp
* @date 2025-02-11
*/
@Component
public class OrdinaryStrategy extends BaseMember implements Strategy {
@Override
public BigDecimal quote(BigDecimal price) {
this.exec();
return price;
}
@Override
public void afterPropertiesSet() throws Exception {
StrategyFactory.register("1",this);
}
}
具体策略2
package com.geekmice.springbootmybatiscrud.strategy.fifth;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* @author mbp
* @date 2025-02-11
*/
@Component
public class GoldStrategy extends BaseMember implements Strategy {
@Override
public BigDecimal quote(BigDecimal price) {
BigDecimal res = price.multiply(new BigDecimal("0.8"));
this.exec();
return res;
}
@Override
public void afterPropertiesSet() throws Exception {
StrategyFactory.register("2", this);
}
}
具体策略3
package com.geekmice.springbootmybatiscrud.strategy.fifth;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* @author mbp
* @date 2025-02-11
*/
@Component
public class PlatinumStrategy extends BaseMember implements Strategy {
@Override
public BigDecimal quote(BigDecimal price) {
BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));
return res;
}
@Override
public void afterPropertiesSet() throws Exception {
StrategyFactory.register("3", this);
}
}
测试类
package com.geekmice.springbootmybatiscrud.controller;
import com.geekmice.springbootmybatiscrud.dao.StudentMapper;
import com.geekmice.springbootmybatiscrud.pojo.Student;
import com.geekmice.springbootmybatiscrud.strategy.fifth.Strategy;
import com.geekmice.springbootmybatiscrud.strategy.fifth.StrategyFactory;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author Administrator
*/
@RestController
@RequestMapping("/student")
public class StudentController {
@Resource
private StudentMapper studentMapper;
@GetMapping(value = "queryAll")
public List<Student> queryAll() {
Strategy strategyService = StrategyFactory.getStrategyService("1");
System.out.println(strategyService.quote(new BigDecimal("1000")));
Strategy strategyService2 = StrategyFactory.getStrategyService("2");
System.out.println(strategyService2.quote(new BigDecimal("1000")));
Strategy strategyService1 = StrategyFactory.getStrategyService("3");
System.out.println(strategyService1.quote(new BigDecimal("1000")));
return new ArrayList<>();
}
}
优化3:传递策略类型
根据某个策略类型,执行某个策略逻辑
思路:需要保证某个类型对应某个策略类,通过spring
中InitializingBean
接口初始化bean
,项目启动过程执行实现InitializingBean
接口中的afterPropertiesSet
方法,在这个方法中初始化map中指定的策略。
策略接口
public interface Strategy extends InitializingBean {
BigDecimal quote(BigDecimal price);
}
策略工厂
package com.geekmice.springbootmybatiscrud.strategy.fourth;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class StrategyFactory {
/**
* 设置策略map
*/
private static Map<String, Strategy> strategyMap = new HashMap<>(16);
public static Strategy getStrategyService(String type) {
return strategyMap.get(type);
}
/**
* 提前策略装入 strategyMap
*/
public static void register(String type, Strategy strategy) {
if (Objects.isNull(type)) {
return;
}
strategyMap.put(type, strategy);
}
}
具体策略1
package com.geekmice.springbootmybatiscrud.strategy.fourth;
import com.geekmice.springbootmybatiscrud.strategy.third.PayStrategy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class OrdinaryStrategy implements Strategy {
@Override
public BigDecimal quote(BigDecimal price) {
// System.out.println("都要处理的内容");
return price;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("11111111111");
StrategyFactory.register("1",this);
}
}
具体策略2
package com.geekmice.springbootmybatiscrud.strategy.fourth;
import com.geekmice.springbootmybatiscrud.strategy.third.PayStrategy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class GoldStrategy implements Strategy {
@Override
public BigDecimal quote(BigDecimal price) {
BigDecimal res = price.multiply(new BigDecimal("0.8"));
return res;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("222222222222");
StrategyFactory.register("2",this);
}
}
具体策略3
package com.geekmice.springbootmybatiscrud.strategy.fourth;
import com.geekmice.springbootmybatiscrud.strategy.third.PayStrategy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class PlatinumStrategy implements Strategy {
@Override
public BigDecimal quote(BigDecimal price) {
// 都要处理的内容
// System.out.println("都要处理的内容");
BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));
return res;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("3333333333333");
StrategyFactory.register("3",this);
}
}
测试
package com.geekmice.springbootmybatiscrud.controller;
import com.geekmice.springbootmybatiscrud.dao.StudentMapper;
import com.geekmice.springbootmybatiscrud.pojo.Student;
import com.geekmice.springbootmybatiscrud.strategy.first.StrategyFactory;
import com.geekmice.springbootmybatiscrud.strategy.fourth.Strategy;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author Administrator
*/
@RestController
@RequestMapping("/student")
public class StudentController {
@Resource
private StudentMapper studentMapper;
@GetMapping(value = "queryAll")
public List<Student> queryAll() {
Strategy strategyService =StrategyFactory.getStrategyService("1");
System.out.println(strategyService);
System.out.println(strategyService.quote(new BigDecimal("1000")));
return new ArrayList<>();
}
}