设计模式: 工厂方法模式(Factory Method Pattern) + 策略模式(Strategy Pattern)

基础概念

工厂方法模式(Factory Method Pattern)

也被称为多态工厂模式,其定义了一个创建某种产品的接口,但由子类决定要实例化的产品是哪一个,从而把产品的实例化推迟到子类

策略模式(Strategy Pattern)

定义了一组策略,分别在不同类中封装起来,每种策略都可以根据当前场景相互替换,从而使策略的变化可以独立于操作者。

使用场景

工厂模式一般配合策略模式一起使用,当系统中有多种产品(策略),且每种产品有多个实例时,此时适合使用工厂模式:每种产品对应的工厂提供该产品不同实例的创建功能,从而避免调用方和产品创建逻辑的耦合,完美符合迪米特法则(最少知道原则)。

定义抽象产品(策略)

public interface Strategy<T> {

    /**
     * Get identify
     *
     * @return ID
     */
    T getId();
}

定义抽象策略工厂

通过组合方式将引入当前工厂中的产品(策略)类型

public class StrategyFactory<T, S extends Strategy<T>> implements InitializingBean, ApplicationContextAware {

    private Map<T, S> strategyFactory;

    private final Class<S> strategyType;

    private ApplicationContext context;

    /**
     * Get Strategy by id
     *
     * @param id identify of strategy
     * @return strategy
     */
    public S getStrategy(T id) {
        return strategyFactory.get(id);
    }

    /**
     * Strategy type
     *
     * @return type of strategy
     */
    protected Class<S> getStrategyType() {
        return this.strategyType;
    }

    public StrategyFactory(Class<S> strategyType) {
        this.strategyType = strategyType;
    }

    @Override
    public void afterPropertiesSet() {
        Collection<S> values = context.getBeansOfType(getStrategyType()).values();
        strategyFactory = Maps.newHashMapWithExpectedSize(values.size());
        values.forEach(item -> strategyFactory.put(item.getId(), item));
    }

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

业务实战

定义策略

public interface PaymentTypeStrategy extends Strategy<String> {
    /**
     * Get payment type
     *
     * @return payment type
     */
    String getPaymentType();

    /**
     * Do pay
     */
    void doPay();

    /**
     * Get id of Payment Type
     *
     * @return ID
     */
    @Override
    default String getId() {
        return getPaymentType();
    }
}

放入Spring容器

@Configuration
public class StrategyFactoryConfig {

    @Bean
    public StrategyFactory<String, PaymentTypeStrategy> getPaymentTypeFactory() {
        return new StrategyFactory<>(PaymentTypeStrategy.class);
    }
}

具体业务实现

CASE 1:

@Component
@Slf4j
public class PayByStripeStrategy implements PaymentTypeStrategy {
    @Override
    public String getPaymentType() {
        return "Stripe";
    }

    @Override
    public void doPay() {
        log.info("Start pay by: {}", getPaymentType());
    }
}

CASE 2:

@Component
@Slf4j
public class PayByCheckoutStrategy implements PaymentTypeStrategy {
    @Override
    public String getPaymentType() {
        return "Checkout";
    }

    @Override
    public void doPay() {
        log.info("Start pay by: {}", getPaymentType());
    }
}

测试

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {StrategyFactoryConfig.class, PayByStripeStrategy.class, PayByCheckoutStrategy.class})
public class PaymentTypeStrategyTest {

    @Resource
    private StrategyFactory<String, PaymentTypeStrategy> factory;

    @Test
    public void testStripePayStrategy() {
        PaymentTypeStrategy strategy = factory.getStrategy("Stripe");
        strategy.doPay();
    }
14:25:38.946 [main] INFO com.th.test.pattern.strategy.paymenttype.impl.PayByStripeStrategy - Start pay by: Stripe
posted @ 2022-12-07 14:17  AaronTanooo  阅读(196)  评论(0)    收藏  举报