一、设计模式一策略模式定义
策略模式的目的是封装一系列的算法,它们具有共性,可以相互替换,也就是说让算法独立于使用它的客户端而独立变化,客户端仅仅依赖于策略接口 。
汇总:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。 策略模式把对象本身和运算规则区分开来,因此我们整个模式也分为三个部分。
1).环境类(Context):用来操作策略的上下文环境。
2).抽象策略类(Strategy):策略的抽象。
3).具体策略类(ConcreteStrategy):具体的策略实现。
例如:解析报文,为MT1101时是A,为MT1102是B,如上所说,解析报文的可以分为三个方面
解析器(操作策略的上下文环境)、解析方式(策略的抽象)、解析方式的实现(具体的策略实现)。
或者 学生选择交通方式去上学,公交/地铁/打车。
二、策略模式+Map字典解决if-else
现在根据解析报文的动作来代码实践,优化if-else操作。
首先,环境类(Context):用来操作策略的上下文环境,也就是解析器
/**
* 描述: 上下文类,持有策略接口
*
* 环境类(Context):用来操作策略的上下文环境,也就是解析器
*
* @author: yanglin
* @Date: 2020-06-30-13:16
* @Version: 1.0
*/
@Component
public class ReceiptStrategyContext {
private IReceiptHandleStrategy receiptHandleStrategy;
/**
* 设置策略接口
* @param receiptHandleStrategy
*/
public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy){
this.receiptHandleStrategy = receiptHandleStrategy;
}
/**
* 执行接口
* @param receipt
*/
public void handleReceipt(Receipt receipt){
receiptHandleStrategy.handleReceipt(receipt);
}
}
抽象策略类(Strategy):策略的抽象。 也就是解析方式接口
@Service
public interface IReceiptHandleStrategy {
void handleReceipt(Receipt receipt);
}
具体策略类(ConcreteStrategy):具体的策略实现。解析方式的实现。
@Slf4j
@IsElseEnd(type = "MT1101")
public class Mt1101ReceiptHandleStrategy implements IReceiptHandleStrategy{
public static Mt1101ReceiptHandleStrategy newReceiptHandleStrategy(){
return new Mt1101ReceiptHandleStrategy();
}
@Override
public void handleReceipt(Receipt receipt) {
log.info("Mt1101ReceiptHandleStrategy 解析报文MT1101 : {}", receipt.getMessage());
}
}
@Slf4j
@IsElseEnd(type = "MT2101")
public class Mt2101ReceiptHandleStrategy implements IReceiptHandleStrategy{
public static Mt2101ReceiptHandleStrategy newReceiptHandleStrategy(){
return new Mt2101ReceiptHandleStrategy();
}
@Override
public void handleReceipt(Receipt receipt) {
log.info("Mt2101ReceiptHandleStrategy 解析报文MT2101 : {}", receipt.getMessage());
}
}
@Slf4j
@IsElseEnd(type = "MT8104")
public class Mt8104ReceiptHandleStrategy implements IReceiptHandleStrategy{
public static Mt8104ReceiptHandleStrategy newReceiptHandleStrategy(){
return new Mt8104ReceiptHandleStrategy();
}
@Override
public void handleReceipt(Receipt receipt) {
log.info("Mt8104ReceiptHandleStrategy 解析报文MT8104 : {}", receipt.getMessage());
}
}
@Slf4j
@IsElseEnd(type = "MT9999")
public class Mt9999ReceiptHandleStrategy implements IReceiptHandleStrategy{
public static Mt9999ReceiptHandleStrategy newReceiptHandleStrategy(){
return new Mt9999ReceiptHandleStrategy();
}
@Override
public void handleReceipt(Receipt receipt) {
log.info("Mt9999ReceiptHandleStrategy 解析报文MT9999 : {}", receipt.getMessage());
}
}
再来个策略工厂,处理数据。
/**
* 描述: 策略工厂
*
* 具体策略类(ConcreteStrategy):具体的策略实现,每一种出行方式的具体实现。
*
* @author: yanglin
* @Date: 2020-06-30-13:19
* @Version: 1.0
*/
@Component
@Slf4j
public class ReceiptHandleStrategyFactory {
public Map<String, IReceiptHandleStrategy> receiptHandleStrategyMap;
public static ReceiptHandleStrategyFactory newReceiptHandleStrategyFactory(){
return new ReceiptHandleStrategyFactory();
}
/**
* 初始化加载IsElseEnd注解对应的类
*/
private ReceiptHandleStrategyFactory() {
receiptHandleStrategyMap = new ConcurrentHashMap<>();
try{
// 1.反射工具包,扫描注解插入语数据
//反射工具包,指明扫描路径
Reflections reflections = new Reflections("com.yl.strategy");
//获取带Handler注解的类
Set<Class<?>> classList = reflections.getTypesAnnotatedWith(IsElseEnd.class);
for (Class classes : classList) {
IsElseEnd annotation = (IsElseEnd) classes.getAnnotation(IsElseEnd.class);
String type = annotation.type();
receiptHandleStrategyMap.put(type, (IReceiptHandleStrategy) classes.newInstance());
log.info("addListType type : {}, ", type);
}
}catch (Exception e){
e.printStackTrace();
}
// 2.这是写死数据
/*receiptHandleStrategyMap.put("MT1101", Mt1101ReceiptHandleStrategy.newReceiptHandleStrategy());
receiptHandleStrategyMap.put("MT2101", Mt2101ReceiptHandleStrategy.newReceiptHandleStrategy());
receiptHandleStrategyMap.put("MT8104", Mt8104ReceiptHandleStrategy.newReceiptHandleStrategy());
receiptHandleStrategyMap.put("MT9999", Mt9999ReceiptHandleStrategy.newReceiptHandleStrategy());*/
}
public IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){
return receiptHandleStrategyMap.get(receiptType);
}
}
或者使用springAop切面获取数据
@Component
@Aspect
@Slf4j
public class IfElseAspect {
/**
* 包名的方式
* @Pointcut("execution(* com.yl.strategy.service.impl.*.*(..))")
* 注解发送
* @Pointcut("@annotation(com.yl.strategy.annotation.IsElseEnd)")
*/
@Pointcut("execution(* com.yl.strategy.service.impl.*.*(..))")
public void addListType(){
}
@Before("addListType()")
public void doBefore(JoinPoint joinPoint) {
log.info("******拦截前的逻辑******");
log.info("目标方法名为:" + joinPoint.getSignature().getName());
log.info("目标方法所属类的简单类名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
log.info("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
log.info("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
//获取传入目标方法的参数
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
log.info("第" + (i + 1) + "个参数为:" + args[i]);
}
log.info("被代理的对象:" + joinPoint.getTarget());
log.info("代理对象自己:" + joinPoint.getThis());
}
/**
* 环绕通知
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("addListType()&&@annotation(com.yl.strategy.annotation.IsElseEnd))")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
Object res = null;
long time = System.currentTimeMillis();
try {
res = joinPoint.proceed();
time = System.currentTimeMillis() - time;
// 得到类注解 获得所在切点的该类的class对象,也就是UserController这个类的对象
Class<?> aClass = joinPoint.getTarget().getClass();
IsElseEnd annotationClass = aClass.getAnnotation(IsElseEnd.class);
if (Objects.nonNull(annotationClass)) {
String type = annotationClass.type();
// 将类型增加到Map集合中
ReceiptHandleStrategyFactory.newReceiptHandleStrategyFactory()
.receiptHandleStrategyMap.put(type, (IReceiptHandleStrategy) aClass.newInstance());
log.info("addListType type : {}, time : {} ", type, time);
}
// 得到方法注解
/**
* MethodSignature signature = (MethodSignature) joinPoint.getSignature();
* IsElseEnd annotation = signature.getMethod().getAnnotation(IsElseEnd.class);
*/
return res;
} finally {
try {
}catch (Exception e){
log.info("IfElseAspect 操作失败:" + e.getMessage());
e.printStackTrace();
}
}
}
@After("addListType()")
public void doAfter() {
log.info("******拦截后的逻辑******");
}
}
IsElseEnd 注解类
// 接口、类、枚举、注解
@Target(ElementType.TYPE)
// 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用.
@Retention(RetentionPolicy.RUNTIME)
public @interface IsElseEnd {
String type() default "";
}
回执生成器,创建测试数据。
@Data
@Accessors()
public class Receipt {
/**
* 回执信息
*/
String message;
/**
* 回执类型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`)
*/
String type;
static Receipt newReceipt(){
return new Receipt();
}
public static Builder builder(){
return new Builder();
}
public static class Builder{
private String message;
private String type;
public Builder message(String message){
this.message = message;
return this;
}
public Builder type(String type){
this.type = type;
return this;
}
public Receipt build(){
Receipt receipt = newReceipt();
receipt.setMessage(message);
receipt.setType(type);
return receipt;
}
}
}
public class ReceiptBuilder {
public static List generateReceiptList(){
//直接模拟一堆回执对象
List receiptList = new ArrayList<>();
receiptList.add(Receipt.builder().message("我是MT2101回执喔").type("MT2101").build());
receiptList.add(Receipt.builder().message("我是MT1101回执喔").type("MT1101").build());
receiptList.add(Receipt.builder().message("我是MT8104回执喔").type("MT8104").build());
receiptList.add(Receipt.builder().message("我是MT9999回执喔").type("MT9999").build());
return receiptList;
}
}
最后测试一波
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class StrategyTest {
@Autowired
ReceiptHandleStrategyFactory receiptHandleStrategyFactory;
@Test
public void strategyRun() throws Throwable {
//模拟回执
List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();
//策略上下文
ReceiptStrategyContext receiptStrategyContext = new ReceiptStrategyContext();
// ReceiptHandleStrategyFactory receiptHandleStrategyFactory = ReceiptHandleStrategyFactory.newReceiptHandleStrategyFactory();
for (Receipt receipt : receiptList) {
//获取并设置策略
IReceiptHandleStrategy receiptHandleStrategy = receiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());
receiptStrategyContext.setReceiptHandleStrategy(receiptHandleStrategy);
//执行策略
receiptStrategyContext.handleReceipt(receipt);
}
}
}
三、分析策略模式
策略模式的优点:
①我们之前在选择出行方式的时候,往往会使用if-else语句,也就是用户不选择A那么就选择B这样的一种情况。 这种情况耦合性太高了,而且代码臃肿,有了策略模式我们就可以避免这种现象。
②策略模式遵循开闭原则,实现代码的解耦合。扩展新的方法时也比较方便,只需要继承策略接口就好了。
缺点:
①客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
②策略模式会出现很多的策略类。
③context在使用这些策略类的时候,这些策略类由于继承了策略接口,所以有些数据可能用不到,但是依然初始化了。 3.2.与其他模式的区别
1).与状态模式的区别
策略模式只是条件选择方法,只执行一次方法,而状态模式是随着状态的改变不停地更改执行方法。举个例子, 就好比我们旅游,对于策略模式我们只需要选择其中一种出行方法就好了,但是状态模式不一样,可能我们到了 A地点选择的是火车,到了B地点又选择飞机,根据不同的状态选择不同的出行方式。
2).与工厂模式的区别
工厂模式是创建型模式 ,它关注对象创建,提供创建对象的接口,让对象的创建与具体的使用客户无关。 策略模式是对象行为型模式 ,它关注行为和算法的封装 。再举个例子,还是我们出去旅游,对于策略模式 我们只需要选择其中一种出行方法就好,但是工厂模式不同,工厂模式是你决定哪种旅行方案后,由工厂代替你 去构建具体方案(工厂代替你去买火车票)。
以上