設計模式: 工廠方法模式(Factory Method Pattern) + 策略模式(Strategy Pattern)
阿新 • • 發佈:2022-12-07
目錄
基礎概念
工廠方法模式(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());
}
}