一、基本定义
策略设计模式:“针对”一组算法,“将”每一个算法封装到具有相同接口的独立的类中,“从而”使它们可以相互替换。
二、目的
策略设计模式的重点不是如何实现算法,而是如何组织、调用这些算法。策略设计模式让程序的结构更加灵活,让系统具有更好的灵活性和扩展性,降低需求变动的维护成本。
三、代码实现
策略设计模式代码有三个主体。
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; } }
上述代码可以看到,我们的主函数中(可以理解为Controller中),只有Context类的代码,没有出现具体的策略类。调用Context的result()方法,实际上就是包裹调用策略类的function()方法。这个时候,如果出现需求变动,我们Controller层的代码是不需要变动的,修改的是Context类中的switch()语句。
有同事说策略模式的好处之一就是可以避免 if - else 语句,我是不赞成的,因为不管怎么说,策略模式是根据不同的情况选择不同的策略,那么这个过程必然会有 条件选择语句。if - else 语句也好,swicth语句也好,条件语句经过判断,选择出具体的实现类,因此它们在策略模式中是不可避免的。
四、策略模式的特点
各个封装的算法地位平等,并且同一时刻只能使用其中的一种策略实现类。
它们具有相同的接口,可以相互进行替换。
五、优缺点
优点:由于策略模式的扩展性与灵活性,代码变得便于维护。在实际中,从前端接收一个参数,然后调用简单工厂的构造函数,在简单工厂内部创建这个策略的实例对象,调用简单工厂的方法返回结果即可。代码可参考第二个例子。
缺点:策略模式因为需要将每一个策略都封装成具有相同接口的独立的类,如果当前系统中策略很多,无异于增加了代码开发的量。另外,在调用这些策略的时候,需要对每一个策略都要了解,增加了系统的复杂性。