「聊设计模式」之策略模式(Strategy)
🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!
大家下午好,我是bug菌,今天我们继续聊设计模式。
前言
设计模式是软件工程领域中常用的一种解决问题的方案,它提供了一种通用的解决方案,以便在开发过程中遇到类似的问题时复用。策略模式(Strategy
)是常用的设计模式之一,它提供了一种将算法家族(一组相同的算法)进行封装、动态切换的方法,从而能够根据不同条件选择不同的算法来解决问题。
在本文中,我们将详细介绍策略模式的概念、特点、优缺点以及实现方法,并通过一个简单的Java程序来演示其使用场景。
摘要
策略模式是一种让算法独立于客户端而独立变化的设计模式,它将一组相同的算法进行封装,并将算法的选择与使用分离开来,从而能够灵活地切换不同的算法。
策略模式
策略模式是一种行为型设计模式,它通过定义一组算法家族,封装每个算法,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
模式概念
策略模式(Strategy Pattern
)是一种设计模式,它可以让算法独立于使用它的客户端而变化。在策略模式中,算法被封装成一系列的策略类,每个策略类都实现了同一个接口。客户端可以选择不同的策略来满足不同的需求,在运行时可以动态地切换不同的策略。这样可以避免代码中出现大量的条件语句,提高代码的灵活性和可维护性。此外,策略模式还可以用来解决一些复杂的算法问题,比如排序算法、搜索算法等。
模式结构
在策略模式中,有三个角色:
- 环境(
Context
):封装了需要进行处理的数据,以及选择合适的算法。 - 抽象策略(
Strategy
):定义了一个算法家族,可以被具体的策略(ConcreteStrategy
)所替换。 - 具体策略(
ConcreteStrategy
):实现了抽象策略定义的算法。
如下是策略模式的UML类图:
模式特点
策略模式的核心思想是将算法与使用算法的客户端分离开来,从而达到以下几个特点:
- 策略模式将算法封装在单独的类中,使得代码更加清晰、易于理解和维护。
- 策略模式让算法的变化独立于使用算法的客户端,从而可以灵活地切换或增加新的算法,而不会影响到客户端的代码。
- 策略模式可以避免大量的
if-else
语句,提高代码的可读性和可维护性。
应用场景
策略模式适用于以下场景:
对象有多种行为或算法,需要根据不同情况选择不同的算法。
系统中有多个类实现相同的接口或继承相同的抽象类,但具体实现不同。
需要在运行时动态地添加、删除或切换算法,而不影响客户端代码。
一个类有多种变形或状态,每个状态有不同的行为,需要根据状态动态改变对象的行为。
例如,表单验证可以使用策略模式来实现不同的验证方法,可将每种验证方法封装为一个策略类,然后通过选择不同的策略类来实现不同的验证。又例如,游戏中的角色可以使用策略模式来实现不同的攻击方式,可将每种攻击方式封装为一个策略类,再通过选择不同的策略类来实现不同的攻击方式。
模式优缺点
优点
策略模式具有以下优点:
- 算法独立性:策略模式将算法与客户端分离,从而使得算法可以独立变化,而不会影响到客户端的代码。
- 可扩展性:可以方便地增加或替换算法,从而满足不同的需求。
- 容易维护:策略模式将算法的实现封装在单独的类中,使得代码更加清晰、易于理解和维护。
缺点
策略模式的缺点在于:
- 客户端需要知道所有的策略,并选择合适的算法。如果算法的数量庞大,将会增加客户端的复杂性。
- 策略模式会增加系统中类的数量。
策略模式代码实现
在Java中,可以使用接口来定义抽象策略(Strategy
)以及具体策略(ConcreteStrategy
),然后使用一个Context类来包含需要处理的数据,并调用具体策略的方法来处理数据。
下面是一个简单的示例,它实现了一个可以根据不同的策略选择不同的计算方法来计算两个数的和:
抽象策略
package com.example.javaDesignPattern.strategy;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 15:31
*/
public interface Strategy {
int doOperation(int num1, int num2);
}
具体策略1
package com.example.javaDesignPattern.strategy;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 15:32
*/
public class OperationAdd implements Strategy {
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
具体策略2
package com.example.javaDesignPattern.strategy;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 15:32
*/
public class OperationSubtract implements Strategy {
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
Context类
package com.example.javaDesignPattern.strategy;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 15:32
*/
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
测试代码
package com.example.javaDesignPattern.strategy;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 15:32
*/
public class StrategyTest {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
}
}
执行结果如下:
代码解释:
在上述代码中,抽象策略(Strategy
)是一个接口,它定义了一个抽象的doOperation
方法。具体策略(ConcreteStrategy
)实现了这个接口,并实现了具体的算法。Context
类包含一个Strategy
对象,并在执行策略时调用具体策略的doOperation
方法。
测试代码实例化了两个Context
对象,分别传入了不同的具体策略,然后调用executeStrategy
方法来执行算法。
测试用例
使用Junit编写测试用例,对于上述的代码进行测试,保证程序的正确性。
public class StrategyTest {
@Test
public void testAdd() {
Context context = new Context(new OperationAdd());
assertEquals(context.executeStrategy(10, 5), 15);
}
@Test
public void testSubtract() {
Context context = new Context(new OperationSubtract());
assertEquals(context.executeStrategy(10, 5), 5);
}
}
测试执行截图如下:
测试代码解析
这是一个Java
测试类,包含两个测试方法:testAdd()
和testSubtract()
,用于测试不同策略下的数学运算结果是否正确。
测试方法中通过创建一个Context
对象并指定不同的策略对象来执行对应的数学运算,并使用assertEquals()
方法来断言实际结果与期望结果是否一致。其中,Context
类封装了策略接口,并提供了executeStrategy(int num1, int num2)
方法来执行具体的数学运算。而OperationAdd
和OperationSubtract
则是具体的策略实现类,分别用于执行加法和减法运算。
这是一个简单的策略模式示例,其核心思想是在运行时动态地选择不同的行为。 通过将具体算法封装在策略接口和实现类中,并在Context
对象中维护策略对象的引用,可以方便地切换和替换具体的算法实现,从而实现了算法的灵活性和可扩展性。
小结
策略模式是一种行为型设计模式,它将算法独立于客户端而存在,在策略模式中,算法被封装进一系列的策略类中,客户端可以选择不同的策略来满足不同的需求,从而灵活地切换或增加新的算法,避免代码中出现大量的条件语句,提高代码的可读性和可维护性。策略模式的核心思想是将算法与使用算法的客户端分离开来,从而达到算法独立性、可扩展性、容易维护等优点。在Java中,使用接口来定义抽象策略以及具体策略,然后使用一个Context类来包含需要处理的数据,并调用具体策略的方法来处理数据。通过编写测试用例,可以保证代码的正确性。
附录源码
如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。
总结
策略模式是常用的一种设计模式,它能够将算法家族进行封装,并使其可以相互替换。策略模式真正的优点在于,它能够将算法的选择与使用分离开来,从而可以灵活地切换不同的算法,而不会影响到客户端的代码。在实际开发中,我们可以使用接口来实现抽象策略和具体策略,然后使用一个Context类来进行调用。
当然,策略模式也有其缺点,如需要客户端知道所有的策略等。但总体来说,策略模式能够使代码更加灵活、易于扩展和维护。
☀️建议/推荐你
如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
📣关于我
我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。
- 点赞
- 收藏
- 关注作者
评论(0)