代码之家  ›  专栏  ›  技术社区  ›  Vasu

带命令模式的SpringBeans映射

  •  1
  • Vasu  · 技术社区  · 6 年前

    我已经得到 ProductHandler 用不同的实现类,例如, ABCProductHandler , DEFProductHandler 等。正在从调用 ProductServiceImpl 使用命令模式初始化,如图所示 here .

    ProductServiceImpl类:

    @Service
    public class ProductServiceImpl implements ProductService {
    
        private Map<ProductType,ProductHandler> productHandlersMap = 
                                             new EnumMap<>(ProductType.class);
    
        private ABCProductHandler abcProductHandler;
    
        private DEFProductHandler defProductHandler;
    
        //....10 other product handlers goes here
    
        @Autowired
        public ProductServiceImpl(ABCProductHandler abcProductHandler, 
                                      DEFProductHandler defProductHandler, .....) {
            this.abcProductHandler = abcProductHandler;
            this.defProductHandler = defProductHandler;
            //....10 other product handlers goes here
        }
    
        @PostConstruct() 
        public void init() {
            productHandlersMap.put(ProductType.ABC, abcProductHandler);
            productHandlersMap.put(ProductType.DEF, defProductHandler);
            //....10 other product handlers goes here
        }
    
        @Override
        public ProductDetails calculateProductPrice(ProductType productType) {
            productHandlersMap.get(productType).calculate();
            //..some otehr code goes here
            return productDetails;
        }
    }
    

    不过,我对上述情况并不满意 产品服务实施 因为有很多 productHandlersMap.put 使用样板代码调用。

    现在,我的问题是,有没有任何方法可以加载 productHandlersMap 容易吗?

    @Service
    public class ProductServiceImpl implements ProductService {
    
        private Map<ProductType,ProductHandler> productHandlersMap = 
                            new EnumMap<>(ProductType.class);
    
        @PostConstruct() 
        public void init() {
             //How to laod productHandlersMap easily with 
             // different ProductHandler types here?
        }
    
        @Override
        public ProductDetails calculateProductPrice(ProductType productType) {
            productHandlersMap.get(productType).calculate();
            //..some other code goes here
            return productDetails;
        }
    }
    
    2 回复  |  直到 6 年前
        1
  •  2
  •   fps    6 年前

    Spring可以自动连接实现接口的bean的不同实现 I 到类型的属性 Map<String, I> 自动,其中键是 豆子的名字 以及bean实例的值。因为您已经有了一个枚举来针对每个枚举 ProductHandler 实现,您可以利用它:

    public enum ProductType {
        ABC(ProductType.ABC_BEAN_NAME),
        DEF(ProductType.DEF_BEAN_NAME);
    
        public static final String ABC_BEAN_NAME = "abcProductHandler";
        public static final String DEF_BEAN_NAME = "defProductHandler";
    
        private String beanName;
    
        ProductType(String beanName) { this.beanName = beanName; }
    
        public String beanName() { return beanName; }
    }
    

    然后,定义你的不同 生产商 实现 @Configuration 工厂级或通过 @Service @Component 注释:

    @Service(ProductType.ABC_BEAN_NAME)
    public class ABCProductHandler implements ProductHandler {
    
        // ...
    }
    
    @Service(ProductType.DEF_BEAN_NAME)
    public class DEFProductHandler implements ProductHandler {
    
        // ...
    }
    

    现在,在你 ProductServiceImpl Bean,只需自动连线 Map<String, ProductHandler> :

    @Service
    public class ProductServiceImpl implements ProductService {
    
        private final Map<String, ProductHandler> productHandlersMap;
    
        @Autowired
        public ProductServiceImpl(Map<String, ProductHandler> productHandlersMap) {
            this.productHandlersMap = productHandlersMap;
        }
    
        @Override
        public ProductDetails calculateProductPrice(ProductType productType) {
            productHandlersMap.get(productType.beanName()).calculate();
            //..some otehr code goes here
            return productDetails;
        }
    }
    

    这样,就可以让弹簧完成所有的喷射工作,甚至不需要使用 @PostConstruct 方法。

    注意使用 productType.beanName() 里面 calculateProductPrice 方法。这样可以确保使用正确的bean来计算价格。

        2
  •  1
  •   Anton Kudinov    6 年前

    可以创建弹簧配置组件

    @Configuration
    public class CollectionConfig {
    
        @Bean
        public ProductHandler  getABC() {
            return new ABCProductHandler(ProductType.ABC);
        }
    
        @Bean
        public ProductHandler  getDEF() {
            return new DEFProductHandler(ProductType.DEF);
        }
    
        @Bean
        public ProductHandler  getXYZ() {
            return new XYZProductHandler(ProductType.XYZ);
    
        }
     
    
        // other factory methods
    
    }
    

    之后:

        @Service 
    public class ProductServiceImpl implements ProductService { 
    private Map<ProductType,ProductHandler> productHandlersMap = new EnumMap<>(ProductType.class); 
    
     @Autowired(required = false)
     private List<ProductHandler> beanList;
    
     @PostConstruct() 
    public void init() { 
        beanList.foreach(b->
        productHandlersMap.put(b.getType(), b))
         }
    }