项目场景:
提示:这里简述项目相关背景:
示例:商城系统有会员系统,不同会员有不同优惠程度,普通会员不优惠;黄金会员打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{@Overridepublic 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{@Overridepublic 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 {@Overridepublic 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{@Overridepublic 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 {@Overridepublic BigDecimal quote(BigDecimal price) {this.exec();return price;}@Overridepublic 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 {@Overridepublic BigDecimal quote(BigDecimal price) {BigDecimal res = price.multiply(new BigDecimal("0.8"));this.exec();return res;}@Overridepublic 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 {@Overridepublic BigDecimal quote(BigDecimal price) {BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));return res;}@Overridepublic 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 {@Resourceprivate 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 {@Overridepublic BigDecimal quote(BigDecimal price) {
// System.out.println("都要处理的内容");return price;}@Overridepublic 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 {@Overridepublic BigDecimal quote(BigDecimal price) {BigDecimal res = price.multiply(new BigDecimal("0.8"));return res;}@Overridepublic 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 {@Overridepublic BigDecimal quote(BigDecimal price) {// 都要处理的内容// System.out.println("都要处理的内容");BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));return res;}@Overridepublic 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 {@Resourceprivate 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<>();}}