карта бобов весны с шаблоном команды - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть класс ProductHandler с различными реализациями, такими как, например, ABCProductHandler, DEFProductHandler и т. Д., Которые вызываются из класса ProductServiceImpl с использованием шаблона команды, как показано здесь .

Класс 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;
    }
}

Однако я не доволен вышеупомянутым классом ProductServiceImpl, так как существует множество вызовов 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 ]

0 голосов
/ 11 февраля 2019

Spring может автоматически связывать различные реализации компонента, который реализует интерфейс I, со свойством типа Map<String, I> автоматически, где ключом является имя компонента и значение экземпляра компонента.Поскольку у вас уже есть перечисление для каждой реализации 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; }
}

Затем определите свои различные реализации ProductHandler либо в классе фабрики @Configuration, либо с помощьюаннотации @Service или @Component:

@Service(ProductType.ABC_BEAN_NAME)
public class ABCProductHandler implements ProductHandler {

    // ...
}

@Service(ProductType.DEF_BEAN_NAME)
public class DEFProductHandler implements ProductHandler {

    // ...
}

Теперь, в вашем бобе ProductServiceImpl, просто автоматически подключите 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;
    }
}

Таким образом, вы 'Позвольте Spring сделать всю работу по внедрению, и нет необходимости даже использовать метод @PostConstruct.

Обратите внимание на использование productType.beanName() внутри метода calculateProductPrice.Это гарантирует, что вы используете правильный бин для расчета цены.

0 голосов
/ 11 февраля 2019

Вы можете создать компонент конфигурации пружины

@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))
     }
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...