策略模式
好处:可以减少if else,新增策略只需新增实现类和枚举。
缺点:类增多了。
实现策略模式所需的类
- 策略枚举类
- 策略接口类
- 策略实现类
- 策略上下文
策略枚举类
后面会用到枚举作为策略Map的key,策略实现类作为value,形成一对一的关系,便于根据策略类型获取策略实现类。
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 策略枚举
*/
@Getter
@AllArgsConstructor
public enum TestEnum {
/**
* 一
*/
ONE(1, "策略一"),
/**
* 二
*/
TWO(2, "策略二");
private Integer code;
private String description;
/**
* 根据编码找枚举
* @param code 编码
* @return 匹配不到返回null
*/
public static TestEnum getByCode(Integer code) {
return Arrays.stream(TestEnum.values()).filter(t -> code.equals(t.code)).findFirst().orElse(null);
}
}
策略接口类
提供接口给策略实现类实现。(听君一席话,如听一席话 hhhh)
import com.sc.cloud.common.enums.TestEnum;
/**
* 策略接口
*/
public interface TestStrategy {
/**
* 获取策略类型
* @date 2022/9/14
* @return com.sc.cloud.common.enums.TestEnum
*/
TestEnum getType();
/**
* 随便打印些东西
* @date 2022/9/14
*/
void print();
}
策略实现类
通过getType()
方法将枚举与实现类关联起来。
策略一实现类:
import com.sc.cloud.common.enums.TestEnum;
import com.sc.cloud.strategy.TestStrategy;
import org.springframework.stereotype.Service;
/**
* 策略一实现类
*/
@Service
public class OneStrategyImpl implements TestStrategy {
@Override
public TestEnum getType() {
return TestEnum.ONE;
}
@Override
public void print() {
System.out.println("策略一");
}
}
策略二实现类:
import com.sc.cloud.common.enums.TestEnum;
import com.sc.cloud.strategy.TestStrategy;
import org.springframework.stereotype.Service;
/**
* 策略而实现类
*/
@Service
public class TwoStrategyImpl implements TestStrategy {
@Override
public TestEnum getType() {
return TestEnum.TWO;
}
@Override
public void print() {
System.out.println("策略二");
}
}
策略上下文
通过Spring的构造注入将实现了策略接口的类放到strategyList中,使用时再根据策略类型获取对应的实现类,执行对应的策略方法。
import com.sc.cloud.common.enums.TestEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* 策略上下文
*/
@Component
public class TestStrategyContext {
private final ConcurrentHashMap<TestEnum, TestStrategy> strategy = new ConcurrentHashMap<>();
/**
* 构造注入所有实现了策略接口的类
* @param strategyList 所有实现 TestStrategy 接口的类
*/
@Autowired
public TestStrategyContext(List<TestStrategy> strategyList) {
strategyList.forEach(s -> strategy.put(s.getType(), s));
}
/**
* 对外部调用提供方法
* @param type 策略类型
*/
public void print(Integer type) {
TestEnum testEnum = TestEnum.getByCode(type);
if (Objects.isNull(testEnum)) {
System.out.println("策略匹配失败");
return;
}
TestStrategy testStrategy = strategy.get(testEnum);
testStrategy.print();
}
}
策略模式 + 工厂模式
参考自:Spring boot 运用策略模式实现,避免多次使用if
参考作者:我赢了算我输
实现策略模式所需的类
与本文第一种策略模式比较,在其基础上新增一个策略工厂类。
- 策略枚举类
- 策略接口类
- 策略实现类
- 策略工厂类
- 策略上下文
支付策略枚举类
此处的className
可以使用Spring默认的bean名称,也可以自定义bean名称,如weChatPayStrategyImpl
为默认名称,wechatPayStrategy
则为自定义的bean名称。
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付策略枚举类
*/
@Getter
@AllArgsConstructor
public enum PayStrategyEnum {
// /**
// * 微信支付
// */
// WECHAT_PAY("wechat","wechatPayStrategy","微信支付"),
// /**
// * 支付宝支付
// */
// ALIPAY("alipay","alipayStrategy","支付宝支付")
// ;
/**
* 微信支付
*/
WECHAT_PAY("wechat", "weChatPayStrategyImpl", "微信支付"),
/**
* 支付宝支付
*/
ALIPAY("alipay", "aliPayStrategyImpl", "支付宝支付");
private String code;
private String className;
private String info;
}
支付策略接口
与本文第一种策略模式比较,不需要提供获取策略类型接口,因为策略用的Map的key是策略实现类的bean名称。
/**
* 支付策略接口
*/
public interface PayStrategy {
boolean pay();
}
支付宝支付策略类
注意:可以给bean重命名,也可以不重命名,此处没有自定义bean名称,使用默认的bean名称,默认的bean名称开头字母是小写,即默认bean名称为aliPayStrategyImpl
。
import com.sc.cloud.strategy.PayStrategy;
import org.springframework.stereotype.Service;
/**
* 支付宝支付策略类
*/
//@Service("alipayStrategy") // 重命名bean
@Service()
public class AliPayStrategyImpl implements PayStrategy {
@Override
public boolean pay() {
System.out.println("使用了阿里支付");
return true;
}
}
微信支付策略类
import com.sc.cloud.strategy.PayStrategy;
import org.springframework.stereotype.Service;
/**
* 微信支付策略类
*/
//@Service("wechatPayStrategy") // 重命名bean
@Service()
public class WeChatPayStrategyImpl implements PayStrategy {
@Override
public boolean pay() {
System.out.println("使用微信支付");
return true;
}
}
支付策略工厂类
通过Spring根据bean名称自动注入到payStrategyMap
,若前面指定了策略实现类bean名称,则此处用的就是指定的名称,否则是默认bean名称
import com.sc.cloud.common.enums.PayStrategyEnum;
import com.sc.cloud.strategy.PayStrategy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
/**
* 支付策略工厂类
*/
@Component
public class PayStrategyFactory {
/**
* 通过Spring容器的方式注入
*/
@Resource
private Map<String, PayStrategy> payStrategyMap;
public PayStrategy getPayStrategy(PayStrategyEnum payStrategyEnum) {
if (!payStrategyMap.containsKey(payStrategyEnum.getClassName())) {
System.out.println("没有对应的支付策略,无法进行支付");
return null;
}
return payStrategyMap.get(payStrategyEnum.getClassName());
}
}
支付策略上下文
就这样
mport com.sc.cloud.common.enums.PayStrategyEnum;
import com.sc.cloud.strategy.factory.PayStrategyFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
/**
* 支付策略上下文
*/
@Component
public class PayStrategyContext {
@Autowired
private PayStrategyFactory payStrategyFactory;
/**
* 支付执行
* @param type 支付类型
*/
public boolean payHandle(String type) {
Optional<PayStrategyEnum> payStrategyEnumOptional = Arrays.stream(PayStrategyEnum.class.getEnumConstants())
.filter((e) -> e.getCode().equals(type)).findAny();
if (!payStrategyEnumOptional.isPresent()) {
System.out.println("匹配不到具体支付策略");
return false;
}
PayStrategyEnum payStrategyEnum = payStrategyEnumOptional.get();
PayStrategy payStrategy = payStrategyFactory.getPayStrategy(payStrategyEnum);
if (Objects.isNull(payStrategy)) {
System.out.println("具体支付策略未实现");
return false;
}
boolean pay = payStrategy.pay();
return true;
}
}