1. 程式人生 > 其它 >設計模式: 工廠方法模式(Factory Method Pattern) + 策略模式(Strategy Pattern)

設計模式: 工廠方法模式(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());
    }
}

測試