[디자인 모델] --- 전략 모델 실전: 자바 에서 if - else 를 대체 하 는 큰 논리

43371 단어 디자인 모드
자바 에 서 는 if - else 의 큰 논리 대신 정책 모드 를 사용 합 니 다.
질문:
자바 는 원래 대상 을 대상 으로 하 는 언어 이지 만 많은 사람들 이 자바 가 대상 을 대상 으로 한다 고 말 한 다음 에 표 맵 실 체 를 제외 하고 다른 것 은 과정 을 대상 으로 하 는 사고 이다.예 를 들 어 오늘 말 하고 자 하 는 것 처럼 코드 의 큰 부분 인 if - else 판단 은 모든 if - else 코드 블록 에 복잡 한 논리 가 많아 서 전체 코드 가 혼 란 스 럽 고 다른 사람 이 보면 똥 같은 코드 를 보 는 것 처럼 느껴 집 니 다.
그렇다면 이 코드 들 을 어떻게 우아 하 게 대체 할 수 있 을 까? 사실은 디자인 모델 (전략 모델) 이 있 으 면 이 문 제 를 잘 해결 할 수 있다.
상황 예:
예 를 들 어 주문 처리, 주문 서 는 여러 type 상태 가 있 습 니 다. 예 를 들 어 type = 1 일 때 일반 주문 의 논 리 를 수행 합 니 다.type: 2 시 판 촉 주문 을 만 감 하 는 논 리 를 실행 합 니 다.type = 3 시 판 촉 주문 서 를 가득 채 우 는 논 리 를 실행 합 니 다.등등, type 은 수 십 가지, 심지어 더 많은 상황 이 있 을 수 있 습 니 다.
그리고 어떤 사람들 은 if - else 를 시작 합 니 다. 예 를 들 어 다음 과 같은 위조 코드 가 있 습 니 다.
if(type=1){
	    ...100}else if(type=2){
	      ...100}else if(type=3){
	      ...100}else if(type=n){
	...(            )
}

잘 하면 if - else 코드 블록 에서 의 논 리 를 하나씩 추출 하 는 방법 으로 약간 뚜렷 한 코드 가 있 지만 모두 과정 을 향 한 사상 입 니 다.나 는 이런 상황 은 다음 과 같은 방식, 즉 if - else 를 전략 모델 로 대체 하여 진정 으로 대상 을 대상 으로 해 야 한다 고 생각한다.각 유형의 주문 서 를 하나의 대상 으로 추출 한 다음 에 서로 다른 주해 표 지 를 통 해 호출 을 구분한다.
if - else 대신 정책 모드:
우선, 이번 사례 는 Spring - boot 프레임 을 사 용 했 으 며, 친 측 은 문제 가 없다.SpringMVC 프레임 도 괜 찮 을 거 예요.하나의 주문 클래스 를 정의 합 니 다. 그 안에 type 속성 이 있 습 니 다. type 은 '1', '2', '3' 일 수 있 습 니 다. 추상 적 인 추상 적 인 AbstractHandler 를 정의 합 니 다. 그 안에 추상 적 인 방법 handle 이 있 습 니 다. 가입 은 주문 클래스 에서 하나의 주해 Handler Type 을 정의 하고 하나의 value 속성 이 있 습 니 다. value 는 몇 가지 가 이 주해 의 이런 유형 을 대표 하 는 주문 정의 일반 클래스 Handler Impl 01 입 니 다.AbstractHandler 를 실현 하고 일반 주문, 즉 @ Handler Type ("1") 을 대표 합 니 다.일반 클래스 HandlerImpl 02 를 정의 하고 AbstractHandler 를 실현 하 며 판 촉 주문 서 를 만 감 하 는 것 을 대표 합 니 다. 즉, @ HandlerType ("2") 입 니 다.일반 클래스 HandlerImpl 03 을 정의 하고 AbstractHandler 를 실현 하 며 판 촉 주문 서 를 가득 채 우 는 것 을 대표 합 니 다. 즉, @ HandlerType ("3") 입 니 다.초기 화 클래스 HandlerProcessor 를 정의 하고 BeanFactory PostProcessor 를 실현 합 니 다. 과정 은 다음 과 같 습 니 다.서로 다른 type 에 대응 하 는 다른 종 류 를 저장 하기 위 한 것 이 분명 합 니 다.클래스 Handler Context 를 정의 합 니 다. handlerMap 이라는 맵 형식의 속성 이 있 습 니 다. getInstance 방법 이 있 습 니 다. 입력 은 type 이 고 AbstractHandler 로 돌아 갑 니 다.마지막 으로 사용 할 때 handler Context. getInstance 방법 을 호출 하여 type 에 따라 대응 하 는 Abstract Handler 를 가 져 옵 니 다.그리고 그의 handle 방법 을 호출 하여 주문 유형 에 대한 처리 논 리 를 실행 합 니 다.
구체 적 인 코드 는 다음 과 같다.
//@Data lombok   ,      get/set  
@Data
public class OrderDTO {
    private String code;
    private BigDecimal price;
    /**
     *     
     * 1:    
     * 2:    
     * 3:    
     */
    private String type;
}
public abstract class AbstractHandler {
    abstract public String handle(OrderDTO orderDTO);
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandlerType {
    String value();
}
@Component
@HandlerType("1")
public class HandlerImpl01 extends AbstractHandler {
    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("  type 1   ,orderDTO.type="+orderDTO.getType());
        return "success";
    }
}
@Component
@HandlerType("2")
public class HandlerImpl02 extends AbstractHandler {
    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("  type 2   ,orderDTO.type="+orderDTO.getType());
        return "success";
    }
}
@Component
@HandlerType("3")
public class HandlerImpl03 extends AbstractHandler {
    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("  type 3   ,orderDTO.type="+orderDTO.getType());
        return "success";
    }
}
@Component
@SuppressWarnings("unchecked")
public class HandlerProcessor implements BeanFactoryPostProcessor {
	//      handler        ,        
    private static final String HANDLER_PACKAGE = "com.zs.handler";
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String, Class> handlerMap = new HashMap<>();
		//   
        ClassScaner.scan(HANDLER_PACKAGE,HandlerType.class).forEach(clazz ->{
            Annotation annotation = clazz.getAnnotation(HandlerType.class);
            HandlerType handlerType = (HandlerType) annotation;
            String type = handlerType.value();
            System.out.println(type);
            handlerMap.put(type,clazz);
        });
        HandlerContext handlerContext = new HandlerContext(handlerMap);
		//    
        beanFactory.registerSingleton(HandlerContext.class.getName(),handlerContext);
    }
}
public class HandlerContext {
    private Map<String,Class> handlerMap;

    public HandlerContext(Map<String, Class> handlerMap) {
        this.handlerMap = handlerMap;
    }

    public AbstractHandler getInstance(String type){
        Class clazz = handlerMap.get(type);
        if(clazz == null){
            throw new IllegalArgumentException("  type      ,type:"+type);
        }
        return (AbstractHandler)SpringContextUtils.getBean(clazz);
    }
}

정의 인터페이스:
public interface OrderService {
    /**
     *           
     * @param orderDTO
     * @return
     */
    String handle(OrderDTO orderDTO);
}

구현 인터페이스:
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private HandlerContext handlerContext;

    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("OrderServiceImpl handle       ===");
        AbstractHandler handler = handlerContext.getInstance(orderDTO.getType());
        return handler.handle(orderDTO);
    }
}

패키지 스 캔 도구 종류:
public class ClassScaner implements ResourceLoaderAware {

    private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();

    private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();

    private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);

    public ClassScaner() {

    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        this.metadataReaderFactory = new CachingMetadataReaderFactory( resourceLoader);
    }

//    public final ResourceLoader getResourceLoader() {
//        return this.resourcePatternResolver;
//    }

    public void addIncludeFilter(TypeFilter includeFilter) {
        this.includeFilters.add(includeFilter);
    }

//    public void addExcludeFilter(TypeFilter excludeFilter) {
//        this.excludeFilters.add(0, excludeFilter);
//    }

//    public void resetFilters(boolean useDefaultFilters) {
//        this.includeFilters.clear();
//        this.excludeFilters.clear();
//    }

    public static Set<Class> scan(String basePackage, Class<? extends Annotation>... annotations) {
        ClassScaner cs = new ClassScaner();
        for (Class anno : annotations)
            cs.addIncludeFilter(new AnnotationTypeFilter(anno));
        return cs.doScan(basePackage);
    }

//    public static Set scan(String[] basePackages, Class extends Annotation>... annotations) {
//        ClassScaner cs = new ClassScaner();
//        for (Class anno : annotations)
//            cs.addIncludeFilter(new AnnotationTypeFilter(anno));
//        Set classes = new HashSet();
//        for (String s : basePackages)
//            classes.addAll(cs.doScan(s));
//        return classes;
//    }

    public Set<Class> doScan(String basePackage) {
        Set<Class> classes = new HashSet<Class>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                    + org.springframework.util.ClassUtils
                    .convertClassNameToResourcePath(SystemPropertyUtils
                            .resolvePlaceholders(basePackage))
                    + "/**/*.class";
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);

            for (int i = 0; i < resources.length; i++) {
                Resource resource = resources[i];
                if (resource.isReadable()) {
                    MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                    if ((includeFilters.size() == 0 && excludeFilters.size() == 0)
                            || matches(metadataReader)) {
                        try {
                            classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }
        } catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "I/O failure during classpath scanning", ex);
        }
        return classes;
    }

    protected boolean matches(MetadataReader metadataReader) throws IOException {
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return false;
            }
        }
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return true;
            }
        }
        return false;
    }
}

spring 도구 클래스, bean 가 져 오기 위해
@Component
public class SpringContextUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;
    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanId) {
        return (T) applicationContext.getBean(beanId);
    }
    public static <T> T getBean(Class<T> requiredType) {
        return (T) applicationContext.getBean(requiredType);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }
}

좋은 웹페이지 즐겨찾기