这几天做设计方案的时候,用到了策略模式,今天一起来看看策略模式
策略模式
日常背书:
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
通过优惠券的场景来看下策略模式
在使用优惠券计算商品价格的时候,因为优惠券的种类很多,有现金卷、折扣卷等,每个优惠券计算价格方式都不一样,所以这个场景使用了策略模式来实现,具体包括以下几个要素:
- 优惠券策略抽象类AbstractCouponStrategy,类中定义了一些公共方法,计算价格的抽象方法
/**
* 优惠券策略抽象类
*/
public abstract class AbstractCouponStrategy {
/**
* 通过优惠券信息、订单信息计算价格
* @param couponId
* @param orderId
*/
abstract void calculatedPrice(long couponId,long orderId);
}
- 每个卷种的具体策略实现类ACouponStrategy、BCouponStrategy,主要负责A类型、B类型不同的优惠券计价策略
- ACouponStrategy:
/**
* A优惠券策略类
*/
@Component
public class ACouponStrategy extends AbstractCouponStrategy {
@Override
void calculatedPrice(long couponId, long orderId) {
System.out.println("A类优惠券,这笔订单打八折!");
}
}
- BCouponStrategy:
/**
* B优惠券策略类
*/
@Component
public class BCouponStrategy extends AbstractCouponStrategy {
@Override
void calculatedPrice(long couponId, long orderId) {
System.out.println("B类优惠券,这笔订单减200!");
}
}
- 优惠券策略上下文StrategyContext类,主要负责对各种优惠券信息的处理,操作具体的策略类来进行优惠券订单计价
/**
* 优惠券策略上下文StrategyContext类
*/
@Component
public class CouponStrategyContext {
private AbstractCouponStrategy abstractCouponStrategy;
//用于存储优惠券具体策略,key为优惠券种类,value为优惠券具体策略对象
private static Map<String, AbstractCouponStrategy> map = new HashMap<>();
static {
//初始化,把A类优惠券策略类对象存入map
map.put("a", SpringContext.getBean(ACouponStrategy.class));
//初始化,把B类优惠券策略类对象存入map
map.put("b", SpringContext.getBean(BCouponStrategy.class));
}
public void processOrderAndCoupon(long orderId,long couponId){
System.out.println("先通过订单id orderId获取订单信息," +
"先进行判断是否需要处理等");
System.out.println("再通过优惠券卷码couponId获取优惠券信息," +
"如优惠券类别等,进行一些业务校验、处理");
//如果校验什么都没有问题
//就进行优惠券计价逻辑,假设这里获取的优惠券的种类是A类
//先获取A类的优惠券策略对象 从这个map里面获取,
// 这个入参A是动态的从上面的逻辑里面拿到的,这里演示先写死了
abstractCouponStrategy = map.get("a");
//这里都是演示代码就不进行判空什么的了
abstractCouponStrategy.calculatedPrice(couponId,orderId);
System.out.println("然后在进行一些计价的别的逻辑");
}
}
- SpringContext这个简单说下,就是一个维护了spring中的ApplicationContext对象的上下文对象
@Component
@Lazy(false)
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContext.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
代码码完了,我们先来运行一下:
@RunWith( SpringRunner.class)
@SpringBootTest(classes = BootStartApplication.class)
public class TestCoupon {
@Autowired
private CouponStrategyContext couponStrategyContext;
@Test
public void testStrategy(){
//进行优惠券订单计价
couponStrategyContext.processOrderAndCoupon(214L,356L);
}
}
运行结果如下:
运行结果
这个栗子就讲到这了,我个人的习惯就是会在上下文对象中维护一个map还存储各个具体的策略类对象,在通过一些标识id什么的来获取具体的策略类实现类对象。
策略模式就为大家说到这里,欢迎大家来交流,指出文中一些说错的地方,让我加深认识。
谢谢大家!












网友评论