策略模式的结构
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。下面就以一个示意性的实现讲解策略模式实例的结构。
这个模式涉及到三个角色:
● 环境(Context)角色:持有一个Strategy的引用。
● 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
● 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
源码如下:
1.切面
import java.lang.annotation.*;
/**
* @ClassName AppSource
* @Description 端来源
* @Author zhangs
* @email 853632587@qq.com
* @Date 2021/9/6 19:21
* @Version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface AppSource {
//AppSourceEnum
byte value();
}
2.扫描工具类
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;
public class SpringClassScanner {
/**
* 获取包下所有,标注annotationType 的类
* @param scanPackage 包名
* @param annotationType 注解类型
* @return 满足要求的class set集合
*/
public static Set<Class<?>> findAnnotatedClasses(String scanPackage, Class<? extends Annotation> annotationType) {
ClassPathScanningCandidateComponentProvider provider = createComponentScannerIncludeAnnotation(annotationType);
return getClass(scanPackage, provider);
}
/**
* 获取所有继承clazz的class
* @param scanPackage 包名
* @param clazz 父类class
* @return 满足要求的class set集合
*/
public static Set<Class<?>> findAssignableClass(String scanPackage, Class<?> clazz) {
ClassPathScanningCandidateComponentProvider provider = createComponentScannerIncludeAssignableType(clazz);
return getClass(scanPackage, provider);
}
private static ClassPathScanningCandidateComponentProvider createComponentScannerIncludeAnnotation(Class<? extends Annotation> annotationType) {
// Don't pull default filters (@Component, etc.):
ClassPathScanningCandidateComponentProvider provider
= new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(annotationType));
return provider;
}
private static ClassPathScanningCandidateComponentProvider createComponentScannerIncludeAssignableType(Class<?> clazz) {
// Don't pull default filters (@Component, etc.):
ClassPathScanningCandidateComponentProvider provider
= new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(clazz));
return provider;
}
private static Set<Class<?>> getClass(String scanPackage, ClassPathScanningCandidateComponentProvider provider) {
Set<Class<?>> classSet = new HashSet<>();
for (BeanDefinition beanDef : provider.findCandidateComponents(scanPackage)) {
try {
Class<?> cl = Class.forName(beanDef.getBeanClassName());
classSet.add(cl);
} catch (ClassNotFoundException e) {
//IGNORE
}
}
return classSet;
}
}
3.接口类
import com.xxx.match.message.event.SalesMatchEvent;
import java.io.IOException;
/**
* @ClassName MatchResourceHandler
* @Description No such property: code for class: Script1
* @Author zhangs
* @email 853632587@qq.com
* @Date 2021/9/6 18:37
* @Version 1.0
*/
public interface MatchResourceHandler {
/**
* 处理商机原文(拆词)
* @param event
*/
void resourceMatchEvent(SalesMatchEvent event);
/**
* 写入商机
* @param event
*/
void salesMatchInsertEvent(SalesMatchEvent event) throws IOException;
/**
* 发送商机
* @param event
*/
void SsalesMatchSendEvent(SalesMatchEvent event);
}
4.抽象类(使用公用代码块)
/**
* @ClassName AbstractMatchResourceHandler
* @Description 抽象商机结果集匹配处理
* @Author zhangs
* @email 853632587@qq.com
* @Date 2021/9/6 18:40
* @Version 1.0
*/
public abstract class AbstractMatchResourceHandler implements MatchResourceHandler {
//公用代码块
}
5.实现接口类
import com.alibaba.fastjson.JSON;
import com.xxx.account.sdk.domain.Staff;
import com.xxx.common.sdk.annotation.AppSource;
import com.xxx.common.sdk.constant.BaseConstant;
import com.xxx.common.sdk.redis.JedisTemplate;
import com.xxx.common.sdk.util.DateUtil;
import com.xxx.common.sdk.util.LogUtil;
import com.xxx.match.common.constant.Constant;
import com.xxx.match.message.event.SalesMatchEvent;
import com.xxx.match.message.strategy.ResourceMatchHandlerContext;
import com.xxx.match.rpc.AccountRpc;
import com.xxx.match.service.SalesMatchService;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Objects;
/**
* @ClassName QdMatchResourceHandler
* @Description 企点商机结果集匹配处理
* @Author zhangs
* @email 853632587@qq.com
* @Date 2021/9/6 18:40
* @Version 1.0
*/
@Component
@AppSource(1)//AppSourceEnum
public class QdMatchResourceHandler extends AbstractMatchResourceHandler {
@ApiOperation("处理商机原文-拆词")
@Override
public void resourceMatchEvent(SalesMatchEvent event) {
//业务 代码块
}
@ApiOperation("写入商机")
@Override
public void salesMatchInsertEvent(SalesMatchEvent event) throws IOException {
//业务 代码块
}
@ApiOperation("发送商机")
@Override
public void SsalesMatchSendEvent(SalesMatchEvent event) {
//业务 代码块
}
}
6.实现上下文
import com.xxx.common.sdk.annotation.AppSource;
import com.xxx.common.sdk.util.ApplicationContextUtil;
import com.xxx.common.sdk.util.SpringClassScanner;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @ClassName MatchResourceHandlerContext
* @Description 商机匹配策略模式
* @Author zhangs
* @email 853632587@qq.com
* @Date 2021/9/6 19:31
* @Version 1.0
*/
@Component
public class MatchResourceHandlerContext {
private static final String HANDLER_PACKAGE = "com.xxx.match.message.chain.handler.strategy";
private Map<Byte, Class<?>> handlerMap = new HashMap<>();
@PostConstruct
public void init() {
Set<Class<?>> handlerClass = SpringClassScanner.findAnnotatedClasses(HANDLER_PACKAGE, AppSource.class);
for (Class<?> aClass : handlerClass) {
AppSource appSource = aClass.getAnnotation(AppSource.class);
byte value = appSource.value();
handlerMap.put(value, aClass);
}
}
public MatchResourceHandler getHandler(byte appSource) {
Class<?> handlerClass = handlerMap.get(appSource);
return (MatchResourceHandler) ApplicationContextUtil.getBean(handlerClass);
}
}