一、基本定义
策略设计模式:“针对”一组算法,“将”每一个算法封装到具有相同接口的独立的类中,“从而”使它们可以相互替换。
核心:策略实现相同接口,可以相互替换。即封装的各个算法地位平等,它们具有相同的接口,可以相互进行替换。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiATN381dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yM5AjM1U2NkVzMiZWZjRDZyYzX3QTOwETM4EzLcdDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
二、速记
策略设计模式的重点不是如何实现算法,而是如何组织、调用这些算法。策略设计模式让程序的结构更加灵活,让系统具有更好的灵活性和扩展性,降低需求变动的维护成本。
核心:封装地位相同的各种算法,让它们可以动态的切换。
优点:扩展性很好,增加算法只需要增加一个新的策略实现。
缺点:随着策略越来越多,维护这些的策略也很困难。
场景:用于计算公式经常变动的业务场景,比如学生的学分GPA的计算。
注入:在业务中提供一个策略工厂。在工厂的提供的方法中通过条件来判断应该返回哪一个策略,这样业务代码就不用变动。
三、代码实现
策略设计模式代码有三个主体。
1.持有抽象策略的引用的类
2.抽象策略类
3.具体策略类
范例一:策略模式经典代码
public class Context {
private Stategy stategy;
public Context(Stategy stategy) {
this.stategy = stategy;
}
public int result(){
return stategy.function();
}
//主函数可以视为要被调用的环境,例如Service中,或者是Controller中
public static void main(String[] args) {
Context context = new Context(new Stategy1());
System.out.println(context.result());
}
}
//抽象策略
interface Stategy{
int function();
}
//具体三种策略实现
class Stategy1 implements Stategy{
@Override
public int function() {
return 1;
}
}
class Stategy2 implements Stategy{
@Override
public int function() {
return 2;
}
}
class Stategy3 implements Stategy{
@Override
public int function() {
return 3;
}
}
这个例子里面Context类持有着抽象策略的引用,由构造函数接收抽象策略实现类。Context调用的result()方法,其实就是包裹的策略的function()方法。根据具体情况,选择不同的策略的实现类,传递给Context类的构造器。
范例二:策略模式与简单工厂模式结合
这种方式更加适合与MVC模式。Controller代码中不直接生成相关策略,根据前台传递过来的参数,交由Context类的构造函数,在Context类的内部进行选择具体的实现类。Controller层里面的代码只需要知道Context类,根本不需要知道具体的策略类。在发生需求变动的时候,我们修改的类是Context类的构造函数,修改switch()语句,因此Controller层的代码不需要变动。代码如下:
public class Context {
private Stategy stategy;
public Context(int i) {
switch (i){
case 1:{
stategy = new Stategy1();
break;
}
case 2:{
stategy = new Stategy2();
break;
}
case 3: {
stategy = new Stategy3();
break;
}
default:{
stategy = new Stategy1();
}
}
}
public int result(){
return stategy.function();
}
//此主函数可以看作是要实际应用的环境,比如某个Controller中
public static void main(String[] args) {
Context context = new Context(3);//这个构造函数的参数由前端传递过来
System.out.println("结果是:"+context.result());
}
}
//策略
interface Stategy{
int function();
}
//具体实现三种
class Stategy1 implements Stategy{
@Override
public int function() {
return 1;
}
}
class Stategy2 implements Stategy{
@Override
public int function() {
return 2;
}
}
class Stategy3 implements Stategy{
@Override
public int function() {
return 3;
}
}
上述代码可以看到,我们的主函数中,只有Context类的代码,没有出现具体的策略类。调用Context的result()方法,实际上就是包裹调用策略类的function()方法。这个时候,如果出现需求变动,我们Controller层的代码是不需要变动的,修改的是Context类中的switch()语句。
有同事说策略模式的好处之一就是可以避免 if - else 语句,我是不赞成的,因为不管怎么说,策略模式是根据不同的情况选择不同的策略,那么这个过程必然会有 条件选择语句。if - else 语句也好,swicth语句也好,条件语句经过判断,选择出具体的实现类,因此它们在策略模式中是不可避免的。
四、优缺点
优点:由于策略模式的扩展性与灵活性,代码变得便于维护。在实际中,从前端接收一个参数,然后调用简单工厂的构造函数,在简单工厂内部创建这个策略的实例对象,调用简单工厂的方法返回结果即可。代码可参考第二个例子。
扩展性体现在,当需求发生变动的时候,我们可以添加新的策略实现类,不用修改已有的策略类。
灵活性体现在,我们可以根据需求,切换我们的策略类。
缺点:策略模式因为需要将每一个策略都封装成具有相同接口的独立的类,如果当前系统中策略很多,无异于增加了代码开发的量。另外,在调用这些策略的时候,需要对每一个策略都要了解,增加了系统的复杂性。
刻意练习
(1)策略设计模式的核心。
(2)策略设计模式的优点。
(3)策略设计模式的缺点。
(4)使用场景。
(5)类图
(6)策略类怎么注入到业务中
分割线--------------------------------------------------------------------------------------------
下一篇:工厂设计模式3