策略模式
设想一个场景,商场结账系统设计,如果商场不同的季节或者节日会有不同的促销活动,比如打x折或者满减再或者赠送积分活动,我们难道要每次去重新更换新的程序吗?还是说用工厂模式,将所有的收费方式包含进去,那么如果需要更改促销额度,是不是就要修改工厂,代码就要重新编译部署。像这种我们需要在系统运行中去根据不同的场景使用不同的方案,就有了策略模式。
什么是策略模式?
- 首先,什么是策略模式?策略模式属于行为型模式(一个类的行为或其算法可以在运行时更改)。所谓的策略,其实就是一些有优先级顺序、相互排斥并且可以相互替换的方案的集合。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。
- 在策略模式中,定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,在这里,每一个封装算法的类都可以称之为策略,为了保证这些策略的一致性,一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类。
业务场景
拿外卖会员折扣活动举例,平台商家为了促销,设置多种会员优惠,包含超级会员8折、普通会员9折和普通用户没有折扣三种。用户在付款的时候,平台根据用户的会员等级,就可以知道用户符合哪种折扣策略,进而计算出应付金额。
结构(图摘自大话设计模式)
策略模式中的所有策略是互斥的,同一场景下只能有一种策略生效。
策略模式的应用
- 业务需求中不同场景需要不同的方案,且同时只能有一种方案生效。
- 代码优化(优化if else或者switch case)
策略模式代码实现
首先,最重要的是是有一个策略的接口,用来保证所有策略的一致性。
package com.wlj.strategy;
/**
* @author wlj
* @Classname Strategy
* @Description 策略的接口
* @Date 7/16/2022 11:19 PM
*/
public interface Strategy {
void pay();
}
几种具体的方案:
/**
* @author wlj
* @Classname ConcreteStrategyA
* @Description 普通客户,就全款付
* @Date 7/16/2022 11:22 PM
*/
public class ConcreteStrategyA implements Strategy{
@Override
public void pay() {
System.out.println("方案:全款支付");
}
}
package com.wlj.strategy;
/**
* @author wlj
* @Classname ConcreteStrategyA
* @Description VIP1,8折款付
* @Date 7/16/2022 11:22 PM
*/
public class ConcreteStrategyB implements Strategy{
@Override
public void pay() {
System.out.println("方案:8折支付");
}
}
package com.wlj.strategy;
/**
* @author wlj
* @Classname ConcreteStrategyA
* @Description VIP2,满300减100
* @Date 7/16/2022 11:22 PM
*/
public class ConcreteStrategyC implements Strategy{
@Override
public void pay() {
System.out.println("方案:满300减100");
}
}
Context对象:根据不同场景执行不同策略方案
package com.wlj.strategy;
/**
* @author wlj
* @Classname Context
* @Description 跟随策略去执行不同方案的对象
* @Date 7/16/2022 11:25 PM
*/
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
// 根据不同的场景去调用不同的方案
public void ContextStrategy() {
strategy.pay();
}
}
客户端:
package com.wlj.strategy;
/**
* @author wlj
* @Classname Client
* @Description 客户端
* @Date 7/16/2022 11:29 PM
*/
public class Client {
public static void main(String[] args) {
Context context;
// 第一种
context = new Context(new ConcreteStrategyA());
context.ContextStrategy();
// 第二种
context = new Context(new ConcreteStrategyB());
context.ContextStrategy();
// 第三种
context = new Context(new ConcreteStrategyC());
context.ContextStrategy();
}
}
结果:
方案:全款支付
方案:8折支付
方案:满300减100
另一种常用写法,不至于在客户端出现if else这种过多逻辑
package com.wlj.strategy;
/**
* @author wlj
* @Classname Context2
* @Description 优化if else
* @Date 7/16/2022 11:38 PM
*/
public class Context2 {
private static String customType;
public Context2(String customType) {
this.customType = customType;
}
public void ContextStrategy(){
if(customType.equals("common")){
new ConcreteStrategyA().pay();
}
else if(customType.equals("vip1")){
new ConcreteStrategyB().pay();
}
else {
new ConcreteStrategyC().pay();
}
}
}
客户端
package com.wlj.strategy;
/**
* @author wlj
* @Classname Client2
* @Description 客户端不会出现过多if else逻辑
* @Date 7/16/2022 11:43 PM
*/
public class Client2 {
public static void main(String[] args) {
String customerType = "common";
new Context2(customerType).ContextStrategy();
// if else写法
if(customerType.equals("common")){
new ConcreteStrategyA().pay();
}
else if(customerType.equals("vip1")){
new ConcreteStrategyB().pay();
}
else {
new ConcreteStrategyC().pay();
}
}
}