14.策略者模式设计思想
目录介绍
- 01.策略模式基础介绍
- 1.1 策略模式由来
- 1.2 策略模式定义
- 1.3 策略模式场景
- 1.4 策略模式思考
- 1.5 策略模式的重心
- 1.6 理解策略唯一性
- 1.7 主要解决的问题
- 02.策略模式原理
- 2.1 罗列一个场景
- 2.2 用例子理解策略
- 2.3 需求普通实现
- 2.4 案例演变实现
- 2.5 策略模式实现步骤
- 03.策略模式结构
- 3.1 策略标准案例
- 3.2 策略模式结构图
- 3.3 策略模式时序图
- 04.策略模式案例
- 4.1 业务需求分析
- 4.2 业务基础实现
- 4.3 用策略模式实现
- 4.4 还有优化空间吗
- 4.5 策略模式缓存
- 05.策略者模式分析
- 5.1 策略模式的优点
- 5.2 策略模式的缺点
- 5.3 适用环境
- 5.4 策略模式与状态模式
- 5.5 策略模式与模版模式
- 5.6 思考题考察
- 06.观察者模式总结
- 6.1 总结一下学习
- 6.2 更多内容推荐
推荐一个好玩网站
一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网
关于设计模式,所有的代码都放到了该项目。设计模式大全
01.策略模式基础介绍
1.0 本博客AI摘要
策略模式是一种行为型设计模式,用于定义一系列可互换的算法,并使它们可以独立于使用它们的客户端而变化。本文档详细介绍了策略模式的基础概念、原理、结构及应用案例,包括折扣计算、文件排序等实际场景,帮助读者深入理解策略模式的实现和优势。此外,并提供了相关代码示例。适合初学者和有一定经验的开发者参考。
1.1 策略模式由来
完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。
有许多算法可以实现某一功能,如查找、排序等,一种常用的方法是硬编码(Hard Coding)在一个类中。实现方式如下:
- 如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,
- 通过if…else…等条件判断语句来进行选择。这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。 在这个算法类中封装了大量查找算法,该类代码将较复杂,维护较为困难。
为了解决这些问题,可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法。
在这里,每一个封装算法的类我们都可以称之为策略(Strategy),为了保证这些策略的一致性,一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类。
1.2 策略模式定义
策略模式(Strategy Pattern):更多内容
定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
策略模式属于对象的行为模式。
其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
1.3 策略模式场景
在以下情况下可以使用策略模式:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 当一个类有多种行为或算法,并且这些行为或算法可以在运行时切换时
- 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。
再继续抽象一下,策略模式的应用场景主要包括以下两种:更多内容
- 行为切换:当系统的许多类的区别仅在于其行为不同时,可以使用策略模式将这些不同的行为动态地让用户对象在其间进行选择。
- 算法选择:在需要动态地在几种算法中选择一种的场景下,也可以使用策略模式。
1.4 策略模式思考
策略模式主要是解决避免 if-else 分支判断逻辑的吗?
实际上,这种认识是很片面的。策略模式主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。
除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险。
策略模式是否支持多态的使用?
通过让环境类持有一个抽象策略类(超类)的引用,在生成环境类实例对象时,让该引用指向具体的策略子类。再对应的方法调用中,就会通过Java的多态,调用对应策略子类的方法。
从而可以相互替换,不需要修改环境类内部的实现。同时,在有新的需求的情况下,也只需要修改策略类即可,降低与环境类之间的耦合度。
1.5 策略模式的重心
策略模式的重心是什么?更多内容
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
1.6 理解策略唯一性
运行时策略的唯一性:运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
1.7 主要解决的问题
策略模式是一种行为型设计模式,它主要用于解决算法选择问题。其主要特点在于能够将一系列算法封装起来,并让它们可以互相替换或独立于使用它的客户而变化。
02.策略模式原理
2.1 罗列一个场景
假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。
一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂。更多内容
比如,本网站可能对所有的高级会员提供每本20%的促销折扣;对中级会员提供每本10%的促销折扣;对钻石会员提供30%的促销折扣;对初级会员没有折扣。
2.2 用例子理解策略
根据描述,折扣是根据以下的几个算法中的一个进行的:
- 算法一:对初级会员没有折扣。
- 算法二:对中级会员提供10%的促销折扣。
- 算法三:对高级会员提供20%的促销折扣。
- 算法四:对钻石会员提供30%的促销折扣。
2.3 需求普通实现
看下面代码,利用面向对象设计原则如何改进,可以保证代码后期的拓展性和解耦问题?
将不同对象分类的服务方法进行抽象,把业务逻辑的紧耦合关系拆开,实现代码的隔离保证了方便的扩展? 看看下面这段代码,改编某伟大公司产品代码,你觉得可以利用面向对象设计原则如何改进?
//将策略的定义、创建、使用直接耦合在一起。
private void calcPrice(int type,double booksPrice) {
double price;
if (type == 1) {
price = booksPrice * 0.9;
System.out.println("对中级会员提供10%的促销折扣");
} else if (type == 2) {
price = booksPrice * 0.8;
System.out.println("对高级会员提供20%的促销折扣");
} else if (type == 3) {
price = booksPrice * 0.7;
System.out.println("对钻石会员提供30%的促销折扣");
} else {
System.out.println("对初级会员没有折扣");
price = booksPrice;
}
System.out.println("图书的最终价格为:" + price);
}
然后测试案例如下所示:
private void test() {
calcPrice(2,300);
}
打印数据如下所示:
对高级会员提供20%的促销折扣
图书的最终价格为:240.0
问题分析一下,如果再多增加几种优惠类型,那么业务就更加复杂了。你在添加if-else分支会让逻辑更加复杂,在维护和拓展这块,将会导致代码越来越臃肿!
2.4 案例演变实现
使用策略模式来实现的结构图如下:
代码案例如下所示
利用开原则,可以尝试改造为下面的代码。更多内容将不同对象分类的服务方法进行抽象,把业务逻辑的紧耦合关系拆开,实现代码的隔离保证了方便的扩展。
抽象折扣类。这个相当于抽象策略
public interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
double calcPrice(double booksPrice);
}
初级会员折扣类。这个是具体策略1
public class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于初级会员的没有折扣");
return booksPrice;
}
}
中级会员折扣类。这个是具体策略2
public class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于中级会员的折扣为10%");
return booksPrice * 0.9;
}
}
高级会员折扣类。这个是具体策略3
public class AdvancedMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于高级会员的折扣为20%");
return booksPrice * 0.8;
}
}
价格类。这个相当于环境角色
public class Price {
//持有一个具体的策略对象
private MemberStrategy strategy;
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
}
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}
然后测试案例如下所示:
private void test() {
//选择并创建需要使用的策略对象
MemberStrategy strategy = new AdvancedMemberStrategy();
//创建环境
Price price = new Price(strategy);
//计算价格
double quote = price.quote(300);
System.out.println("图书的最终价格为:" + quote);
}
打印数据如下所示:
对于高级会员的折扣为20%
图书的最终价格为:240.0
2.5 策略模式实现步骤
策略模式实现步骤
- 定义策略接口或抽象类。定义一个抽象的策略接口或抽象类,其中声明了一个抽象的算法方法。
- 实现具体策略类。实现具体的策略类,这些类实现了策略接口或抽象类中定义的算法。
- 定义环境类。定义一个环境类,持有一个抽象策略类的引用,用于调用具体的策略类中实现的算法。
- 在环境类中使用策略类。在环境中根据不同的场景使用策略类。更多内容
03.策略模式结构
3.1 策略标准案例
策略模式官方实现案例如下所示
抽象策略类定义了一个算法族,其中每个算法都是一个方法。抽象策略类通过抽象方法来约束具体策略类的行为。
public interface Strategy{
void algorithm();
}
具体策略类实现了抽象策略类中定义的算法,每个具体策略类都实现了一种算法。
public static class ConcreteStrategyA implements Strategy {
@Override
public void algorithm() {
System.out.println("use algorithm A");
}
}
public static class ConcreteStrategyB implements Strategy {
@Override
public void algorithm() {
System.out.println("use algorithm B");
}
}
环境类持有一个抽象策略类的引用,用于调用具体的策略类中实现的算法。更多内容
public static class Context {
private final Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void algorithm() {
strategy.algorithm();
}
}
测试一下,结果如下所示:
private void test() {
//创建策略
Strategy strategy = new ConcreteStrategyA();
//创建环境
Context context = new Context(strategy);
//执行行为
context.algorithm();
}
3.2 策略模式结构图
策略模式包含如下角色:
- 环境(Context)角色:持有一个Strategy的引用,即具有复杂多变行为的对象。
- 抽象策略(Strategy)角色:抽象策略类,这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
- 具体策略(ConcreteStrategy)角色:具体策略类,包装了相关的算法或行为。一般实际场景中会有多个
策略模式结构图
3.3 策略模式时序图
策略模式时序图
04.策略模式案例
4.1 业务需求分析
业务需求:你需要在文件中排序文件内容,在案例中文件可能会很大,如果是你,你会怎么做?更多内容
思路分析:只需要将文件中的内容读取出来,并且通过逗号分割成一个一个的数字,放到内存数组中,然后编写某种排序算法(比如快排),或者直接使用编程语言提供的排序函数,对数组进行排序,最后再将数组中的数据写入文件就可以了。
- 比如有 10GB 大小,因为内存有限(比如只有 8GB 大小),我们没办法一次性加载文件中的所有数据到内存中,这个时候,我们就要利用外部排序算法。
- 比如有100GB大小,我们为了利用CPU多核的优势,可以在外部排序的基础之上进行优化,加入多线程并发排序的功能,这就有点类似“单机版”的 MapReduce。
- 比如有1TB大小,即便是单机多线程排序,这也算很慢了。这个时候,我们可以使用真正的 MapReduce 框架,利用多机的处理能力,提高排序的效率。
4.2 业务基础实现
用最简单直接的方式将它实现出来。更多内容
具体代码我贴在下面了,你可以先看一下。因为我们是在讲设计模式,不是讲算法,所以,在下面的代码实现中,我只给出了跟设计模式相关的骨架代码,并没有给出每种排序算法的具体代码实现。
public static class Sorter {
private static final long GB = 1000 * 1000 * 1000;
public void sortFile(String filePath) {
// 省略校验逻辑
File file = new File(filePath);
long fileSize = file.length();
if (fileSize < 6 * GB) { // [0, 6GB)
quickSort(filePath);
} else if (fileSize < 10 * GB) { // [6GB, 10GB)
externalSort(filePath);
} else if (fileSize < 100 * GB) { // [10GB, 100GB)
concurrentExternalSort(filePath);
} else { // [100GB, ~)
mapreduceSort(filePath);
}
}
private void quickSort(String filePath) {
// 快速排序
}
private void externalSort(String filePath) {
// 外部排序
}
private void concurrentExternalSort(String filePath) {
// 多线程外部排序
}
private void mapreduceSort(String filePath) {
// 利用MapReduce多机排序
}
}
在“编码规范”那一部分我们讲过,函数的行数不能过多,最好不要超过一屏的大小。
所以,为了避免 sortFile() 函数过长,我们把每种排序算法从 sortFile() 函数中抽离出来,拆分成 4 个独立的排序函数。
如果只是开发一个简单的工具,那上面的代码实现就足够了。更多内容毕竟,代码不多,后续修改、扩展的需求也不多,怎么写都不会导致代码不可维护。
但是,如果我们是在开发一个大型项目,排序文件只是其中的一个功能模块,那我们就要在代码设计、代码质量上下点儿功夫了。只有每个小的功能模块都写好,整个项目的代码才能不差。
实际上,如果自己实现一下的话,你会发现,每种排序算法的实现逻辑都比较复杂,代码行数都比较多。所有排序算法的代码实现都堆在 Sorter 一个类中,这就会导致这个类的代码很多。
一个类的代码太多也会影响到可读性、可维护性。除此之外,所有的排序算法都设计成 Sorter 的私有函数,也会影响代码的可复用性。更多内容
4.3 用策略模式实现
针对上面的问题,即便我们想不到该用什么设计模式来重构,也应该能知道该如何解决,那就是将 Sorter 类中的某些代码拆分出来,独立成职责更加单一的小类。
实际上,拆分是应对类或者函数代码过多、应对代码复杂性的一个常用手段。按照这个解决思路,我们对代码进行重构。重构之后的代码如下所示:
public class SorterDesign {
private static final long GB = 1000 * 1000 * 1000;
public void sortFile(String filePath) {
// 省略校验逻辑
File file = new File(filePath);
long fileSize = file.length();
ISortAlg sortAlg;
if (fileSize < 6 * GB) { // [0, 6GB)
sortAlg = new QuickSort();
} else if (fileSize < 10 * GB) { // [6GB, 10GB)
sortAlg = new ExternalSort();
} else if (fileSize < 100 * GB) { // [10GB, 100GB)
sortAlg = new ConcurrentExternalSort();
} else { // [100GB, ~)
sortAlg = new MapReduceSort();
}
sortAlg.sort(filePath);
}
}
public interface ISortAlg {
void sort(String filePath);
}
public class QuickSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
public class ExternalSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
public class ConcurrentExternalSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
public class MapReduceSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
经过拆分之后,每个类的代码都不会太多,每个类的逻辑都不会太复杂,代码的可读性、可维护性提高了。
除此之外,我们将排序算法设计成独立的类,跟具体的业务逻辑(代码中的 if-else 那部分逻辑)解耦,也让排序算法能够复用。
这一步实际上就是策略模式的第一步,也就是将策略的定义分离出来。更多内容
4.4 还有优化空间吗
实际上,上面的代码还可以继续优化。
每种排序类都是无状态的,我们没必要在每次使用的时候,都重新创建一个新的对象。所以,我们可以使用工厂模式对对象的创建进行封装。
按照这个思路,我们对代码进行重构。重构之后的代码如下所示:
public class SortAlgFactory {
private static final Map<String, ISortAlg> algs = new HashMap<>();
static {
algs.put("QuickSort", new QuickSort());
algs.put("ExternalSort", new ExternalSort());
algs.put("ConcurrentExternalSort", new ConcurrentExternalSort());
algs.put("MapReduceSort", new MapReduceSort());
}
public static ISortAlg getSortAlg(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
return algs.get(type);
}
}
public class Sorter3 {
private static final long GB = 1000 * 1000 * 1000;
public void sortFile(String filePath) {
// 省略校验逻辑
File file = new File(filePath);
long fileSize = file.length();
ISortAlg sortAlg;
if (fileSize < 6 * GB) { // [0, 6GB)
sortAlg = SortAlgFactory.getSortAlg("QuickSort");
} else if (fileSize < 10 * GB) { // [6GB, 10GB)
sortAlg = SortAlgFactory.getSortAlg("ExternalSort");
} else if (fileSize < 100 * GB) { // [10GB, 100GB)
sortAlg = SortAlgFactory.getSortAlg("ConcurrentExternalSort");
} else { // [100GB, ~)
sortAlg = SortAlgFactory.getSortAlg("MapReduceSort");
}
sortAlg.sort(filePath);
}
}
经过上面两次重构之后,现在的代码实际上已经符合策略模式的代码结构了。
我们通过策略模式将策略的定义、创建、使用解耦,让每一部分都不至于太复杂。
4.5 策略模式缓存
遇到问题:每次创建新的策略类对象都需要消耗一定的时间和内存。如果我们需要多次调用同一个策略类,就会造成资源的浪费。
解决办法:使用策略类的缓存,将已经创建的策略类对象缓存起来,避免重复创建。更多内容
不过,Sorter 类中的 sortFile() 函数还是有一堆 if-else 逻辑。这里的 if-else 逻辑分支不多、也不复杂,这样写完全没问题。
但如果你特别想将 if-else 分支判断移除掉,那也是有办法的。我直接给出代码,你一看就能明白。实际上,这也是基于查表法来解决的,其中的“algs”就是“表”。
public class Sorter4 {
private static final long GB = 1000 * 1000 * 1000;
private static final List<AlgRange> algs = new ArrayList<>();
static {
algs.add(new AlgRange(0, 6*GB, SortAlgFactory.getSortAlg("QuickSort")));
algs.add(new AlgRange(6*GB, 10*GB, SortAlgFactory.getSortAlg("ExternalSort")));
algs.add(new AlgRange(10*GB, 100*GB, SortAlgFactory.getSortAlg("ConcurrentExternalSort")));
algs.add(new AlgRange(100*GB, Long.MAX_VALUE, SortAlgFactory.getSortAlg("MapReduceSort")));
}
public void sortFile(String filePath) {
// 省略校验逻辑
File file = new File(filePath);
long fileSize = file.length();
ISortAlg sortAlg = null;
for (AlgRange algRange : algs) {
if (algRange.inRange(fileSize)) {
sortAlg = algRange.getAlg();
break;
}
}
sortAlg.sort(filePath);
}
private static class AlgRange {
private long start;
private long end;
private ISortAlg alg;
public AlgRange(long start, long end, ISortAlg alg) {
this.start = start;
this.end = end;
this.alg = alg;
}
public ISortAlg getAlg() {
return alg;
}
public boolean inRange(long size) {
return size >= start && size < end;
}
}
}
对于 Sorter 来说,我们可以通过同样的方法来避免修改。更多内容
我们通过将文件大小区间和算法之间的对应关系放到配置文件中。当添加新的排序算法时,我们只需要改动配置文件即可,不需要改动代码。
05.策略者模式分析
5.1 策略模式的优点
策略模式的优点
- 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。更多内容
- 策略模式的优点在于降低系统的耦合度,提高系统的灵活性和扩展性,但增加了系统的复杂性和理解难度。如果使用得当,可以避免使用多重条件语句,如if…else语句、switch…case语句。
5.2 策略模式的缺点
策略模式的缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
- 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。
5.3 适用环境
在以下情况下可以使用策略模式:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。更多内容
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
- 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。
5.4 策略模式与状态模式
策略模式与状态模式有何区别,如下所示:
- 可以通过环境类状态的个数来决定是使用策略模式还是状态模式。
- 策略模式的环境类自己选择一个具体策略类,具体策略类无须关心环境类;而状态模式的环境类由于外在因素需要放进一个具体状态中,以便通过其方法实现状态的切换,因此环境类和状态类之间存在一种双向的关联关系。
- 使用策略模式时,客户端需要知道所选的具体策略是哪一个,而使用状态模式时,客户端无须关心具体状态,环境类的状态会根据用户的操作自动转换。更多内容
- 如果系统中某个类的对象存在多种状态,不同状态下行为有差异,而且这些状态之间可以发生转换时使用状态模式;如果系统中某个类的某一行为存在多种实现方式,而且这些实现方式可以互换时使用策略模式。
5.5 策略模式与模版模式
策略设计模式和模板方法模式都是行为型设计模式,它们都关注于类的行为。它们的区别在于:
- 策略设计模式关注于算法的不同实现,而模板方法模式关注于算法的不同步骤。
- 在策略设计模式中,不同的算法可以自由切换,而在模板方法模式中,算法的不同步骤是固定的,只能在子类中重写。
- 策略设计模式中,客户端需要了解不同的策略类并选择合适的策略类,而在模板方法模式中,客户端不需要了解不同的实现方式。
5.6 思考题考察
需求1: 假设我们正在开发一个计算器程序,该程序可以根据用户的选择进行加、减、乘、除四种运算。如果是你,你该怎么做?
具体实现可以用策略者设计模式来实现。代码可以看:StrategyDesign
需求2: 《三国演义》中刘备前往东吴联姻,诸葛亮派子龙随从,担心主公有失,便给子龙三道锦囊策略,在紧急时候依次打开。你该如何设计实现该需求。
具体实现可以用策略者模式,将三道锦囊做成策略,遇到不同场景执行。具体代码可以看:StrategyDesign
需求3: 例如你要从上海去重庆旅游,在选择交通工具时你可以选择高铁,也可以选择飞机,也可以自己开车自驾游。你要做的是从上海去重庆,在选择交通工具时面临多种选择,每一种选择就是策略。
具体代码可以看:StrategyDesign
06.策略者模式总结
6.1 总结一下学习
01.策略模式基础介绍
由来介绍:完成一项任务,可以有多种不同的方式,每一种方式成为策略,可以根据环境或者条件不同完成不同任务,这个就是策略模式由来!
策略模式定义:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
应用场景:
- 行为切换:当系统的许多类的区别仅在于其行为不同时,可以使用策略模式将这些不同的行为动态地让用户对象在其间进行选择。
- 算法选择:在需要动态地在几种算法中选择一种的场景下,也可以使用策略模式。
策略模式主要是为了解决 if-else 分支判断逻辑的吗?其实除了实现同样功能,重点在于解耦合,让每种策略单独实现,降低代码复杂度,添加或者移除策略时不影响老代码。
策略模式是一种行为型设计模式,它主要用于解决算法选择问题。其主要特点在于能够将一系列算法封装起来,并让它们可以互相替换或独立于使用它的客户而变化。
02.策略模式原理
根据描述,折扣是根据以下的几个算法中的一个进行的:
- 算法一:对初级会员没有折扣。
- 算法二:对中级会员提供10%的促销折扣。
- 算法三:对高级会员提供20%的促销折扣。
- 算法四:对钻石会员提供30%的促销折扣。
第一种实现方式:使用if-else分支实现该业务。如果再多增加几种优惠类型,那么业务就更加复杂了。让逻辑更加复杂,在维护和拓展这块,将会导致代码越来越臃肿!
第二种实现方式:抽象出折扣接口,然后分别创建初级会员策略类,中级会员策略类,高级会员策略类,钻石会员策略类。然后根据环境使用不同策略完善折扣汇算的功能。符合开闭原则,方便拓展,好维护!
03.策略模式结构
策略模式包含如下角色:
- 环境(Context)角色:持有一个Strategy的引用,即具有复杂多变行为的对象。
- 抽象策略(Strategy)角色:抽象策略类,这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
- 具体策略(ConcreteStrategy)角色:具体策略类,包装了相关的算法或行为。一般实际场景中会有多个
05.策略者模式分析
策略模式的优点在于降低系统的耦合度,提高系统的灵活性和扩展性。缺点在于增加了系统的复杂性和理解难度。
6.2 更多内容推荐
模块 | 描述 | 备注 |
---|---|---|
GitHub | 多个YC系列开源项目,包含Android组件库,以及多个案例 | GitHub |
博客汇总 | 汇聚Java,Android,C/C++,网络协议,算法,编程总结等 | YCBlogs |
设计模式 | 六大设计原则,23种设计模式,设计模式案例,面向对象思想 | 设计模式 |
Java进阶 | 数据设计和原理,面向对象核心思想,IO,异常,线程和并发,JVM | Java高级 |
网络协议 | 网络实际案例,网络原理和分层,Https,网络请求,故障排查 | 网络协议 |
计算机原理 | 计算机组成结构,框架,存储器,CPU设计,内存设计,指令编程原理,异常处理机制,IO操作和原理 | 计算机基础 |
学习C编程 | C语言入门级别系统全面的学习教程,学习三到四个综合案例 | C编程 |
C++编程 | C++语言入门级别系统全面的教学教程,并发编程,核心原理 | C++编程 |
算法实践 | 专栏,数组,链表,栈,队列,树,哈希,递归,查找,排序等 | Leetcode |
Android | 基础入门,开源库解读,性能优化,Framework,方案设计 | Android |
23种设计模式
23种设计模式 & 描述 & 核心作用 | 包括 |
---|---|
创建型模式 提供创建对象用例。能够将软件模块中对象的创建和对象的使用分离 |
工厂模式(Factory Pattern) 抽象工厂模式(Abstract Factory Pattern) 单例模式(Singleton Pattern) 建造者模式(Builder Pattern) 原型模式(Prototype Pattern) |
结构型模式 关注类和对象的组合。描述如何将类或者对象结合在一起形成更大的结构 |
适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 过滤器模式(Filter、Criteria Pattern) 组合模式(Composite Pattern) 装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) |
行为型模式 特别关注对象之间的通信。主要解决的就是“类或对象之间的交互”问题 |
责任链模式(Chain of Responsibility Pattern) 命令模式(Command Pattern) 解释器模式(Interpreter Pattern) 迭代器模式(Iterator Pattern) 中介者模式(Mediator Pattern) 备忘录模式(Memento Pattern) 观察者模式(Observer Pattern) 状态模式(State Pattern) 空对象模式(Null Object Pattern) 策略模式(Strategy Pattern) 模板模式(Template Pattern) 访问者模式(Visitor Pattern) |
6.3 更多内容
- GitHub:https://github.com/yangchong211
- 我的编程网站:https://yccoding.com
- 博客汇总:https://github.com/yangchong211/YCBlogs
- 设计模式专栏:https://github.com/yangchong211/YCDesignBlog
- Java高级进阶专栏:https://github.com/yangchong211/YCJavaBlog
- 网络协议专栏:https://github.com/yangchong211/YCNetwork
- 计算机基础原理专栏:https://github.com/yangchong211/YCComputerBlog