一文聊透策略模式

简介: 设计模式系列之策略模式

你好呀,我是Bella酱~

今天我们来一起聊聊策略模式,主要是以下几个方面:定义、生活中的例子、核心组成、UML图、代码实现、适用场景等。

定义

什么是策略模式呢?

引用GoF著作的《设计模式:可复用面向对象软件的基础》中的一段话:

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

什么意思呢?就是说有N个算法,它们要实现的目的是相同的,所以各算法之间是可以互相替换的,每个客户端独立选择使用哪一个算法,不同的客户端之间可以选择不同的算法。

生活中的例子

其实在我们的日常生活中就有很多使用策略模式的例子呢。

例如大多数工作日我们都要做的一个事情,使用某一种交通方式从家去公司。具体使用哪种交通方式呢?根据家到公司的距离,不同的同学会选择不同的交通方式,例如搭乘地铁、自驾、骑行、步行等等。

无论是哪种交通方式,我们的目的是相同的--从家去公司。各种交通方式是独立的,而且是可以互相替换的。每一位同学又会根据个人的实际情况来选择不同的交通方式。这不就是典型的策略模式的例子吗?

核心组成

策略模式主要由4部分组成:

  1. Strategy策略接口。该接口定义了一个方法,各具体策略类会实现该方法。
  2. ConcreteStrategy具体策略。ConcreteStrategy有很多个,它们都实现了Strategy策略接口中定义的方法。
  3. Context上下文。Context中定义了策略类,并且定义了一个方法,该方法在执行时会执行各具体策略中的方法。
  4. Client客户端。Client客户端中会创建Context上下文,并且指定具体策略类,然后再执行Strategy策略接口中定义的方法。

以上文中的例子为例:

  1. Strategy策略接口中定义了一个方法:选择从家去公司的交通方式。
  2. ConcreteStrategy具体策略,例如地铁策略、自驾策略、骑行策略等等,均实现了“选择从家去公司的交通方式”这一方法,但是各具体策略之间的方法体是不同的。
  3. Context上下文中定义了Strategy策略类,同时Context上下文中还有一个方法,该方法会执行Strategy策略接口中定义的方法。
  4. Client客户端中创建Context上下文,并且指定用哪种具体策略,例如指定使用骑行策略,然后调用Context中定义的方法来执行策略中的方法。

UML图

以上文中的例子为例,策略模式的UML图如下:

对UML类图有疑惑的同学可以看下这篇文章:看懂UML图

策略模式UML图.jpg

代码实现

我们来一起看下如何用代码实现上述例子吧,so cool~

首先定义一个Strategy策略接口。

package com.bella.design.patterns.strategy;

/**
 * 策略类
 *
 * @author Bella酱
 * @date 2021/08/08
 */
public interface Strategy {
    /**
     * 选择从家去公司的交通方式
     *
     * @param home    家
     * @param company 公司
     * @return 交通方式
     */
    String selectTransportation(String home, String company);
}

其次定义3个具体策略,分别为SubwayStrategy、CarStrategy、BikeStrategy。
SubwayStrategy地铁策略。

package com.bella.design.patterns.strategy;

import java.text.MessageFormat;

/**
 * 地铁策略
 *
 * @author Bella酱
 * @date 2021/08/08
 */
public class SubwayStrategy implements Strategy {

    /**
     * 选择从家去公司的交通方式
     *
     * @param home    家
     * @param company 公司
     * @return 交通方式
     */
    public String selectTransportation(String home, String company) {
        System.out.println(
                MessageFormat.format("家在-{0}, 公司在-{1},建议您乘坐地铁出行!", home, company));
        return "Subway";
    }
}

CarStrategy自驾策略。

package com.bella.design.patterns.strategy;

import java.text.MessageFormat;

/**
 * 自驾策略
 *
 * @author Bella酱
 * @date 2021/08/08
 */
public class CarStrategy implements Strategy {
    /**
     * 选择从家去公司的交通方式
     *
     * @param home    家
     * @param company 公司
     * @return 交通方式
     */
    public String selectTransportation(String home, String company) {
        System.out.println(
                MessageFormat.format("家在-{0}, 公司在-{1},安全带已系好,秋名山车神准备出发啦!", home, company));
        return "Car";
    }
}

BikeStrategy骑行策略。

package com.bella.design.patterns.strategy;

import java.text.MessageFormat;

/**
 * 骑行策略
 *
 * @author Bella酱
 * @date 2021/08/08
 */
public class BikeStrategy implements Strategy {
    /**
     * 选择从家去公司的交通方式
     *
     * @param home    家
     * @param company 公司
     * @return 交通方式
     */
    public String selectTransportation(String home, String company) {
        System.out.println(
                MessageFormat.format("家在-{0}, 公司在-{1},绿色出行,为环保贡献一份力量!", home, company));
        return "Bike";
    }
}

然后再定义Context上下文。

package com.bella.design.patterns.strategy;

/**
 * 上下文
 *
 * @author Bella酱
 * @date 2021/08/08
 */
public class Context {
    /**
     * 策略
     */
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    /**
     * 选择去公司的交通方式
     *
     * @param home
     * @param company
     * @return
     */
    public String selectTransToCompany(String home, String company) {
        return strategy.selectTransportation(home, company);
    }
}

最后再来一个测试类测下效果~

package com.bella.design.patterns.strategy;

/**
 * 策略模式Test
 *
 * @author Bella酱
 * @date 2021/08/08
 */
public class StrategyTest {
    public static void main(String[] args) {
        Context strategyContext = new Context(new SubwayStrategy());
        String trans = strategyContext.selectTransToCompany("京杭大运河", "未来科技城");
        System.out.println(trans);

        strategyContext = new Context(new CarStrategy());
        trans = strategyContext.selectTransToCompany("老余杭", "未来科技城");
        System.out.println(trans);

        strategyContext = new Context(new BikeStrategy());
        trans = strategyContext.selectTransToCompany("未来科技城", "未来科技城");
        System.out.println(trans);
    }
}

run一下StrategyTest,结果如下:

StrategyTest运行结果.jpg

诺,就是我们想要的效果啦!

适用场景

通过上面的讲解,相信你已经掌握策略模式的使用啦,但是我们应该什么时候使用策略模式呢?

  1. 当一个行为因不同的条件要执行不同的方法体时。其实就是我们平常见到的if else啦。对于项目中的if else语句,可以考虑下是否可以定义不同的具体策略类,然后将else中的语句移入到各个ConcreteStrategy中哦!
  2. 当许多相似的类,仅仅是行为上有差异时。这些相似的类是不是就像各个不同的ConcreteStrategy呢?把那些相似的类利用策略模式重构一波后,代码结构会更加清晰,可读性也会提高很多!
  3. 当对于一个算法,已有几种不同的实现方式,而且后续还可能会增加新的实现方式时。用策略模式,可以在你要新增算法的实现方式时,不修改已有算法的实现,大大降低了引入新策略的风险。

好啦,我们今天的文章就到这里啦,文中涉及的代码都可以从 https://github.com/lilinru/design-patterns 这里下载哦,我们下期见~

相关文章
|
4月前
|
算法 数据安全/隐私保护
行为型 策略模式
行为型 策略模式
27 1
|
设计模式 算法 Java
什么场景要使用策略模式,什么场景不能使用?
如果,让我来设计,我最先想到的就是策略模式。另外,我把往期面试题解析的配套文档我已经准备好,想获得的可以在我的煮叶简介中找到。那么什么场景要使用策略模式,什么场景又不应该使用策略模式呢?我们可以先来看官方对策略模式的定义。
147 0
|
前端开发
策略模式
策略模式
74 0
|
设计模式 算法
策略模式详细介绍
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,并将每个算法封装到具有共同接口的独立类中,使得它们可以互相替换。策略模式可以让算法的变化独立于使用它的客户端。
108 0
|
算法 测试技术 C#
C#策略模式
C#策略模式
58 0
|
设计模式 前端开发
关于策略模式我所知道的
关于策略模式我所知道的
78 0
|
算法 程序员 开发工具
简单说说我对策略模式的了解
简单说说我对策略模式的了解
78 0
|
设计模式 算法
我学会了,策略模式
策略模式属于行为型模式,这个类型的设计模式总结出了 类、对象之间的经典交互方式,将类、对象的行为和使用解耦了,花式的去使用对象的行为来完成特定场景下的功能。
111 0
我学会了,策略模式