设计模式之策略模式
Posted ProChick
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之策略模式相关的知识,希望对你有一定的参考价值。
1.简要概述
- 策略模式也叫作决策模式,属于行为型设计模式。
- 策略模式定义了解决某一个问题的一个算法族,允许用户从该算法族中针对不同的场景选择一个算法解决该问题,同时可以方便的更换算法或者增加新的算法。
- 策略模式会定义一系列算法,然后对其进行封装并使它们可以相互替换,让算法独立于使用它的客户端。
- 策略模式的本质就是将不同的算法进行分离,然后选择性的进行实现。
- 策略模式和状态模式的对象类图类似,并且都是能够动态改变对象的行为。但是状态模式主要是用来解决状态转移的问题,当状态发生变化了,那么对象的行为就会改变;而策略模式主要是用来封装一组可以互相替代的算法族,然后根据需要动态地替换使用的算法。
2.模式结构
👉通常由一个策略接口(
负责定义一个算法族的行为策略方法接口
),多个具体的策略类(负责对特定场景下的问题,将解决的行为方法进行实现
),一个上下文环境类(负责对策略接口进行管理和维护,然后根据不同的请求设置不同的策略做响应处理
),一个客户类(负责调用上下文环境类,然后通过指定某个具体的策略,完成对某个问题的处理
)共同组成。
3.实现代码
举例 💡 :假设现在有一个商店在搞促销活动,但是对于不同的用户来说,折扣的力度是不同的。比如:对于新用户来说可以打7折、对于老用户来说可以打6折,但是对于普通用户来说只能打9折,那么这种打折促销的手段就可以使用策略模式进行处理。
打折策略(策略接口)
public interface DiscountStrategy {
// 定义折扣的方法接口
void discount();
}
普通用户策略(具体策略类)
public class CommonConsumerStrategy implements DiscountStrategy{
@Override
public void discount() {
System.out.println("打九折");
}
}
新用户策略(具体策略类)
public class NewConsumerStrategy implements DiscountStrategy{
@Override
public void discount() {
System.out.println("打七折");
}
}
老用户策略(具体策略类)
public class OldConsumerStrategy implements DiscountStrategy{
@Override
public void discount() {
System.out.println("打六折");
}
}
商店(上下文环境类)
public class Store {
private DiscountStrategy strategy;
// 设置策略
public setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public void selling() {
if (strategy != null){
System.out.println("进行售卖,并" + strategy.discount());
} else {
System.out.println("进行售卖,不打折");
}
}
}
客户类
// 测试客户端
public class StrategyClient{
public static void main(String[] args) {
Store store = new Store();
store.selling(); // 进行售卖,不打折
// 对于普通用户
store.setStrategy(new CommonCustomerStrategy());
store.selling(); // 进行售卖,打九折
// 对于新用户
store.setStrategy(new NewCustomerStrategy());
store.selling(); // 进行售卖,打七折
// 对于老用户
store.setStrategy(new OldCustomerStrategy());
store.selling(); // 进行售卖,打六折
}
}
4.优点好处
- 在策略模式中,我们可以很容易添加新的策略或者修改原有的策略,而不需要改变原有的代码,符合开闭原则。
- 在策略模式中,提供了一种替代继承的方法,而且保持了继承中代码复用的优点。
- 在策略模式中,提供了管理相关的算法族的办法, 然后对算法进行了封装,使得客户端不需要知道算法的具体内部逻辑,提高了算法的保密性和安全性。
- 在策略模式中,避免了程序中使用多重条件转移语句,使得系统更加灵活,并且更加易于扩展。
5.缺点弊端
- 在策略模式中,每针对一种场景都需要创建一个对应的策略类进行实现,所以如果系统中面对某个问题所存在的解决场景有非常多,那么就会导致整个策略方法族非常庞大,不利于后期系统的维护。
- 在策略模式中,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。
6.应用场景
- 当系统中的多个类只区别在表现行为上不同,在运行时需要动态的选择具体要执行的行为的时候,就可以使用策略模式。
- 当系统中需要在不同情况下使用不同的策略,并且可以根据不同的需求,动态的添加新的策略的时候,就可以使用策略模式。
- 当系统需要对客户端隐藏具体策略的实现细节,并使每一种策略可以相互独立替换的时候,就可以使用策略模式。
7.应用示例
JDK源码中对于Arrays.sort方法中传入的Comparator对象进行排序的过程
-
首先看下方的代码,我们通过Arrays.sort方法对变量a这个数组进行排序,然后通过传入不同的排序比较器得到了不同的排序结果。
Integer[] a = new Integer[]{1, 5, 7, 2, 3}; // 从小到大比较器 Comparator<Integer> comparable1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 > o2 ? 1 : -1; } }; // 从大到小比较器 Comparator<Integer> comparable2 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 > o2 ? -1 : 1; } }; Arrays.sort(a, comparable1); // {1, 2, 3, 5, 7} Arrays.sort(a, comparable2); // {7, 5, 3, 2, 1}
-
在这里,Comparator接口就可以看做是策略接口,里面定义了一个compare接口方法。
-
在上面的代码中,我们通过匿名类的形式创建了两个Comparator接口的两个子类,分别对compare方法进行了不同的实现,那这两个类就可以看做是具体的策略类。
-
在Arrays.sort方法的内部,我们可以看到Comparator接口作为方法的形参,会根据传入实现类的不同完成不同的实现,那么Arrays这个类就可以看作是Comparator接口的上下文环境类。
-
所以通过上面的流程分析可以看出,Arrays.sort中关于Comparator的处理过程就采用了策略模式进行实现。
以上是关于设计模式之策略模式的主要内容,如果未能解决你的问题,请参考以下文章