Spring 结合策略模式,如何优雅的实践(普通注入,Map注入,自定义注解注入)

Spring 结合策略模式,如何优雅的实践(普通注入,Map注入,自定义注解注入)

一,认识

掌握注解@Autowired@Resource 基本原理

使用方法

  • @Autowired@Resource注解都是作为bean对象注入的时候使用的。

  • 两者都可以声明在字段和setter方法上

public class  test{
    
    /**字段注入**/
    @Autowired
    private XXXService service;

    /**字段注入**/
    @Resource
    private XXXService service;

    /**构造注入**/
    @Autowired
    public test(XXXService service){
    	this.service = service;
    }
    
 	/**Setter注入**/
    @Autowired
    public void setService(XXXService service) {
        this.service = service;
    }
}

以上三种使用方式 字段注入,构造注入,setter注入。

区别:

  • @Autowired注解是Spring提供的,而@Resource注解是J2EE本身提供的

  • @Autowird注解默认通过byType方式注入,而@Resource注解默认通过byName方式注入

  • @Autowired注解注入的对象需要在IOC容器中存在,否则需要加上属性required=false,表示忽略当前要注入的bean,如果有直接注入,没有跳过,不会报错

其他源码不再撰述,可以自行查看网上相关资料。

掌握策略模式

不了解原理的,可以看我之前写的设计模式,策略博客:地址轻点跳转:https://blog.csdn.net/Crazy_Cw/article/details/106818217

二,实现策略模式

简单通过手动注入bean实现策略模式

定义一个父类接口

public interface Fruits{
    void show();
}

实现接口1

//实现1
@Service
public class Apple implements Fruits {
   @Override
   public void show() {
      System.out.println("我是苹果");
   }
}

实现接口2

//实现2
@Service
public class Banana implements Fruits {
   @Override
   public void show() {
      System.out.println("我是香蕉");
   }
}

创建一个工厂,来实现不同水果

public class IndexMapDataFactory {
     /**使用map,来封装**/	
     private static final Map<Integer, Fruits> MAP_DATA = Maps.newHashMap();
     /**获得不同的实例对象**/	
     private static final Apple service1 = SpringUtil.getBean(Apple.class);
	 /**获得不同的实例对象**/	
     private static final Banana service2 = SpringUtil.getBean(Banana.class);
    
    static {
        MAP_DATA.put(0, service1);
        MAP_DATA.put(1, service2);
    }
    
    /**获得不同的实例对象**/	
    public static Fruits getServiceByType(int type) {
        return MAP_DATA.get(type);
    }
}

我们这里看到工厂类IndexMapDataFactory 里面的不同的实现 通过手动注入, 实在不够优雅。接下来我们来升级

使用注解

这里我们来把工厂类改造一下升级一下,变得更加的优雅

/**记为Spring容器中的一个Bean**/
@Slf4j
@Component
public class StrategyFactory {
    
    /**Spring会将实现注入到该map 里面, key:注入的name,默认类名小写, value:为该实例 **/
    @Resource
    private  Map<String, Fruits> interFaceMap;
    
    public  Fruits getServiceByType(Integer code) {
        String implementName = FruitsTypeEnum.getImplementByCode(code);
        Fruits bean = interFaceMap.get(implementName);
        if(bean == null){
        	log.error("策略工厂bean异常:{} bean is null",implementName);
            throw new RuntimeException("bean is null");
        }
        return bean;
    }
    
    public enum FruitsTypeEnum {
        
        APPLE(1,"apple", "苹果"),
		/**记为Spring容器中的一个Bean**/
        BANANA(2,"banana", "香蕉"),
        
        /**code**/
        public Integer code;

        /**接口的实现类名**/
        public String implement;

        /**备注**/
        public String desc;

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getImplement() {
            return implement;
        }

        public void setImplement(String implement) {
            this.implement = implement;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        FruitsTypeEnum(Integer code, String implement, String desc) {
            this.code = code;
            this.implement = implement;
            this.desc = desc;
        }

        public static String getImplementByCode(Integer code) {
            for (FruitsTypeEnum value : FruitsTypeEnum.values()) {
                if (value.getCode().equals(code)) {
                    return value.getImplement();
                }
            }
            return null;
        }
    }
    
}

使用

public void Controller {
    @Resource
    StrategyFactory strategyFactory;
    
    public void test(int code){
        Fruits  fruits = strategyFactory.getServiceByType(code);
        fruits.show();
    }
}

自定义注解,来优雅实现策略模式

自定义注解

import com.hong.strategy.enums.OrderTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * 自定义策略注解
 */
@Target({ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface FruitsTypeAnnotation {
    
    /**
     * 策略类型
     */
    String fruitsType();
    
}

接口实现

//实现1
@FruitsTypeAnnotation(type = "apple")
@Service
public class Apple implements Fruits {
   @Override
   public void show() {
      System.out.println("我是苹果");
   }
}

//实现2
@FruitsTypeAnnotation(type = "banana")
@Service
public class Banana implements Fruits {
   @Override
   public void show() {
      System.out.println("我是香蕉");
   }
}

一个水果品种实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Type {
   
    private String name;
}

向spring容器中注入

@Component
public class StrategyFactory {
    
    private Map<String, Fruits> map;
    
    @Autowired
    public void setMap(List<Fruits> fruitsInterfaces) {
        map = fruitsInterfaces.stream().collect(
                Collectors.toMap(t -> AnnotationUtils.findAnnotation(t.getClass(), FruitsTypeAnnotation.class).type(),
                        v -> v, (v1, v2) -> v1));
    }


    public void fruitsService(List<Type> list){
        list.forEach(t->{
            //可以根据注解的值判断走哪个实现类,如果有多个实现类就会依次走
            Fruits fruits = map.get(t.getName());
             fruits.show();
        });
    }
}

测试

@Autowired
private StrategyFactory strategyFactory;

@Test
void test(){
    Type apple = new Type("apple");
    Type banana = new Type("banana");
    strategyFactory.fruitsService(Arrays.asList(apple,banana));
}

你可能感兴趣的:(Java,Code,策略模式,spring,java)