设计模式讲解03—策略模式(Strategy)

设计模式讲解03—策略模式(Strategy)

1. 概述定义:策略模式(Strategy Pattern)是一种行为型模式。在这个模式中,会定义一组算法类,将每个算法实现分别封装起来,让它们可以互相替换

解释:在策略模式定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。在策略模式中,我们创建表示各种策略对象和一个行为随着策略对象的改变而改变的 context 对象。不同的策略对象决定不同的 context 对象的执行算法。

2. 简单介绍策略模式主要用于解决:

在多种相似算法存在时,当使用条件语句(如 if ... else ...)导致的复杂性和难以维护的问题使用场景:

当一个系统中有多个类,这些类之间的区别仅在于它们的实现行为实现方式:

定义策略接口:所有策略类都将实现这个统一的接口创建具体策略实现类:每个策略类封装一个不同且具体的算法或行为上下文类:包含一个策略对象的引用,可以通过该引用调用不同的策略常见应用场景:

第三方支付对接:定义一个用于支付的策略接口。不同的支付方式(如:微信支付、支付宝支付)实现不同的策略类,通过一个上下文对象来根据具体的实现调用对应的支付行为等等 ......3. 优缺点优点:

算法切换自由:可以在运行时根据需要切换具体实现算法避免多重条件判断:消除了复杂的条件语句扩展性好:新增算法只需新增一个策略类,无需修改现有代码缺点:

策略类数量增多:每增加一个算法,就需要增加一个策略类所有策略类都需要暴露:策略类需要对外公开,以便可以被选择和使用使用建议:

当系统中有多种算法或行为,且它们之间可以相互替换时,使用策略模式当系统需要动态选择算法时,策略模式是一个合适的选择如果系统中策略类数量过多,考虑使用其他模式或设计技巧来解决类膨胀问题4. 结构策略模式包含以下几个主要角色:

环境(Context):维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象抽象策略(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法具体策略(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的算法实现5. 代码实现5.1. 示例 Demoa. 需求介绍我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类

我们在 main 方法中使用 Context 上下文对象和策略对象来演示 Context 在它所配置或使用的策略发送改变时的行为变化

b. 代码演示创建策略接口,指定策略实现类具有的方法代码语言:javascript复制/**

* @Description 策略接口

* @Author Mr.Zhang

* @Date 2025/5/6 0:36

* @Version 1.0

*/

public interface Strategy {

// 具体的操作由策略类实现

int doOperation(int num1, int num2);

}创建三个具体的策略接口实现类,分别对应加法、减法、乘法操作代码语言:javascript复制/**

* @Description 加法操作

* @Author Mr.Zhang

* @Date 2025/5/6 0:38

* @Version 1.0

*/

public class OperationAdd implements Strategy {

public int doOperation(int num1, int num2) {

return num1 + num2;

}

}代码语言:javascript复制/**

* @Description 减法操作

* @Author Mr.Zhang

* @Date 2025/5/6 0:38

* @Version 1.0

*/

public class OperationSubtract implements Strategy {

public int doOperation(int num1, int num2) {

return num1 - num2;

}

}代码语言:javascript复制/**

* @Description 乘法操作

* @Author Mr.Zhang

* @Date 2025/5/6 0:38

* @Version 1.0

*/

public class OperationMultiply implements Strategy {

public int doOperation(int num1, int num2) {

return num1 * num2;

}

}创建 Context 上下文对象,维护对策略对象的引用代码语言:javascript复制/**

* @Description 工厂类,用来创建策略对象

* @Author Mr.Zhang

* @Date 2025/5/7 21:34

* @Version 1.0

*/

public class StrategyFactory {

private Strategy strategy;

public StrategyFactory(Strategy strategy) {

this.strategy = strategy;

}

public int execute(int num1, int num2) {

return strategy.doOperation(num1, num2);

}

}编写测试代码,测试代码语言:javascript复制/**

* @Description TODO

* @Author Mr.Zhang

* @Date 2025/5/7 21:37

* @Version 1.0

*/

public class Main {

public static void main(String[] args) {

StrategyFactory factory = new StrategyFactory(new OperationAdd());

System.out.println("10 + 5 = " + factory.execute(10, 5));

factory = new StrategyFactory(new OperationSubtract());

System.out.println("10 - 5 = " + factory.execute(10, 5));

factory = new StrategyFactory(new OperationMultiply());

System.out.println("10 * 5 = " + factory.execute(10, 5));

}

}输出

代码语言:javascript复制10 + 5 = 15

10 - 5 = 5

10 * 5 = 50至此,我们已经学会了策略模式的使用。那下面我将再举一个我实际开发中用到的在对接第三方支付时使用到的策略模式的例子

5.2. 应用场景假设我们要做一个多支付方式扣款的功能,需求如下:

设置多个支付方式,包含微信,支付宝,银联其中微信优惠0.5元.支付宝优惠0.7元,银联优惠1元.如果使用微信支付订单满30元优惠0.5元 满50元优惠1元支付宝支付订单满40优惠 0.7元,满80元优惠2元针对这个需求,如果我们直接使用 if...else... 来实现的话无论是可读性还是可维护性都特别低,复杂度较高。那我们完全可以采用 策略模式 + 工厂模式 来进行优化

定义支付策略接口(抽象出策略类所共有的支付方法)代码语言:javascript复制/**

* @author ZGM

* 支付策略接口

*/

public interface PayStrategy {

/**

* 优惠后支付金额

*/

long discountPayMoney(Long money, Integer plat);

}为不同的支付方式创建不同的策略实现类代码语言:javascript复制/**

* 微信支付

*/

@Slf4j

@Component("weChatPay")

public class WeChatPayStrategy implements PayStrategy {

/**

* 优惠后支付金额

* @param money

* @param plat

*/

@Override

public long discountPayMoney(Long money, Integer plat) {

long price=money;

price-=50;

if(订单金额>=50元){

price-=100;

}else if(订单金额>=30元){

price-=50;

}

return price;

}

}代码语言:javascript复制/**

* 银联支付

*/

@Slf4j

@Component("unionpayPay")

public class UnionpayPayStrategy implements PayStrategy {

/**

* 优惠后支付金额

*

* @param money

* @param plat

*/

@Override

public long discountPayMoney(Long money, Integer plat) {

long price=money;

price-=100;

return price;

}

}代码语言:javascript复制/**

* 支付宝支付

*/

@Slf4j

@Component("alipayPay")

public class AlipayPayStrategy implements PayStrategy {

/**

* 优惠后支付金额

*

* @param money

* @param plat

*/

@Override

public long discountPayMoney(Long money, Integer plat) {

long plat=money;

price-=70;

if(订单金额大于>=80元){

price-=200;

}else if(订单金额>=40){

price-=70;

}

return price;

}

}紧接着,创建一个上下文对象,用来指定具体执行的类代码语言:javascript复制/**

*工厂类

*/

@Service

@Slf4j

public class PayFactory {

@Autowired

Map map = new ConcurrentHashMap<>();

@PostConstruct

public void init() {

// 在此处将策略类的实例添加到 map 中

map.put("alipay", new AliPayStrategy());

map.put("wechatpay", new WeChatPayStrategy());

// ...

}

public PayStrategy getStrategy(String componentName) {

PayStrategy strategy= map.get(componentName);

if (strategy == null) {

log.error("没有获取工厂类 componentName={}", componentName);

return null;

}

return strategy;

}

}编写测试代码代码语言:javascript复制@RestController

public class TestController {

@Autowired

PayFactory payFactory;

@RequestMapping(value = "test")

public Long test(Integer plat) {

// plat==0 微信 ,1银联,2支付宝

// 因为策略类组件名不能重复所以我们最好是做一个常量池来进行类型转换.这里就不一一去写了.

PayStrategy alipayPay = payFactory.getStrategy("alipayPay");

Long price = alipayPay.discountPayMoney(10000L);

return price;

}

}输出


相关推荐

IGES(.iges)-Initial Graphics Exchange Specification格式
意大利 1998 主场球衣
苹果4s参数详细参数表(iPhone4s配置参数(详细点))
共享单车涨价,到底啥时候是个头?
人体肾脏位置分布图2022-11-02 9698 阅读
在手机上打开exe文件的三种方法及其安全注意事项