题外话:
本文实非大佬们的科普著作,而是犬余学习过程中的笔记略作润色,内容如有错误或不当之处,欢迎指正。
再此也小推一下本人的公众号,记录一下学习过程,立个flag:坚持学习,每周一更,欢迎监督~
正文:
策略模式(Strategy Pattern)是一种行为型(Behavioral Pattern)的设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端。这种模式是为了实现同一个目标,有多种解决方案或算法的情况下使用的。在策略模式中,主要涉及三类角色:
a. 策略接口(Strategy Interface):这是一个接口,定义了所有支持的算法的公共操作。不同的算法以不同的方式实现这个接口。
b. 具体策略(Concrete Strategies):实现策略接口的类,提供具体的算法实现。每一个类封装了一种具体的算法或行为。
c. 上下文环境(Context):上下文是使用策略的类。它包含一个策略接口的引用,用于运行时切换策略。上下文不知道具体策略的实现细节,它通过策略接口与策略交互。
策略模式的关键点是使得算法可以独立于客户端而变化,也就是说,增加新的算法或者改变算法对客户端没有影响。这样做的好处是可以避免多重条件选择语句,使得代码更加清晰,提高代码的可维护性,并且可以更容易地扩展新的算法。
在软件开发过程中,我们经常需要对某个数组进行排序操作,现在我们需要提供一个工具,使之 可以根据需要动态地切换排序算法,我们写出的代码可能是这样的:
public static List<Integer> sort(List<Integer> list, String algorithm){
if("mp".equals(algorithm)){
System.out.println("使用了冒泡排序");
}else if("ks".equals(algorithm)){
System.out.println("使用了快速排序");
}else if("xz".equals(algorithm)){
System.out.println("使用了选择排序");
}
return list;
}
按照需求来讲,我们确实实现了需要的功能,但是随着需求的迭代,排序算法的总类必然会越来越多,这也就导致了这个sort方法中的ifelse语句越来越长,越来越不易维护;此时带入策略模式的思想,我们会发现,不同的排序算法对我们来讲其实就是不同的策略,那么我们开始对这个方法做一些改进:
首先定义一个用于排序的策略接口:
public interface SortStrategy {
public List<Integer> sort(List<Integer> list);
}
然后实现具体排序类:
public class BubbleSortStrategy implements SortStrategy{
@Override
public List<Integer> sort(List<Integer> list) {
System.out.println("使用了冒泡排序");
return list;
}
}
public class QuickSortStrategy implements SortStrategy{
@Override
public List<Integer> sort(List<Integer> list) {
System.out.println("使用了快速排序");
return list;
}
}
public class SelectionSortStrategy implements SortStrategy{
@Override
public List<Integer> sort(List<Integer> list) {
System.out.println("使用了选择排序");
return list;
}
}
接下来,定义我们排序工具的上下文,指定需要的策略并使用指定的策略进行排序:
public class SortContext {
SortStrategy sortStrategy;
public SortContext(SortStrategy sortStrategy) {
this.sortStrategy = sortStrategy;
}
public void setSortStrategy(SortStrategy sortStrategy) {
this.sortStrategy = sortStrategy;
}
public List<Integer> sort(List<Integer> list){
return this.sortStrategy.sort(list);
}
}
此时,我们可以在客户端代码中使用策略模式来执行排序操作:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
SortContext sortContext = new SortContext(new BubbleSortStrategy());
sortContext.sort(list);
}
在上述代码中,SortStrategy接口即为前面提到过的策略接口(Strategy Interface),它定义了所有排序算法公共功能——排序;而BubbleSortStrategy,QuickSortStrategy以及SelectionSortStrategy三个排序策略的实现类则作为具体策略(Concrete Strategies),他们各自实现了自己的排序算法,在后续的维护中,只需要按需增加新的实现策略即可,而不再需要像之前一样修改公共的ifelse区域代码了;最后的SortContext则扮演着上下文环境(Context)的角色,在运行时可以通过setSortStrategy方法动态地切换使用的排序策略。
而经过以上的说明以及示例,我们可以体会到策略模式具有的一些优点:
- 灵活性:策略模式允许在运行时动态地切换算法或策略,这使得代码更加灵活,可以根据需要选择不同的实现。
- 可维护性:由于每种策略都有自己的类,因此添加新策略或修改现有策略不会影响其他部分的代码,从而提高了代码的可维护性。
- 可扩展性:策略模式使得新的策略可以很容易地添加到系统中,而不需要修改现有的代码。
- 降低耦合度:将不同的算法或策略封装在各自的类中,使得它们与客户端代码之间的耦合度降低,提高了代码的可重用性。
与此同时,它又不可避免地产生了一些缺点:
-
增加了类的数量:每个具体策略都需要一个单独的类,这可能会导致类的数量增加,特别是在策略较多的情况下。
-
客户端必须知道所有的策略:客户端必须了解所有可用的策略,并且负责选择合适的策略,这可能会增加客户端代码的复杂性。
总的来说,策略模式在需要在运行时动态选择算法或策略的情况下非常有用,可以提高代码的灵活性和可维护性。然而,在某些情况下,可能会增加类的数量和客户端代码的复杂性。因此,在使用策略模式时,需要权衡其优点和缺点,选择最适合的设计方案。