设计模式: 工厂方法模式(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

浙公网安备 33010602011771号