1,什么是策略模式?
策略模式,又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
2,策略模式有什么好处?
策略模式的好处在于你可以动态的改变对象的行为。
3,设计原则
设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口(c++z中可以用虚类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。下面是一个例子。
策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响 到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。
4 ,策略模式中有三个对象:
(1)环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
(2)抽象策略对象:它可由接口或抽象类来实现。
(3)具体策略对象:它封装了实现同功能的不同算法。
利用策略模式构建应用程序,可以根据用户配置等内容,选择不同有算法来实现应用程序的功能。具体的选择有环境对象来完成。采用这种方式可以避免由于使用条件语句而带来的代码混乱,提高应用程序的灵活性与条理性。
在我们平时做开发的时候吧,不同的问题有不同的算法来实现。加入有如下问题:有5个小朋友,每个小朋友有5个苹果,计算一下,总共有几个苹果呢?于是,A同学看到之后,很简单啊,这样就ok了:
public class Calculate {
public int calculate(){
int sum = 5+5+5+5+5;
return sum;
}
}
为此,A同学还写好了测试代码,如下:
public class StrategyTest {
public static void main(String[] args) {
Calculate calculate = new Calculate();
System.out.print("apple sum = "+calculate.calculate());
}
}
运行结果是:apple sum = 25,嗯,不错,答案显然是正确的。但此时呢,B同学又说了,我也有一种方法来实现它,在你的基础上改一下就好了,如下:
public class Calculate {
public int calculate(int method){
int sum = 0;
switch (method) {
case 1:
sum = 5+5+5+5+5;
break;
case 2:
sum = 5 *5;
break;
}
return sum;
}
}
运行结果与A同学的方法一致,看来方法也是可行的。但是正所谓,1000个人读哈姆雷特就有1000中体会感受,所以对同一个问题会有不同的算法来能实现,那按上面的写法的话,会使得代码的可读性以及维护拓展降低。所以,遇到这种情况怎么办呢?对,你想到了,策略,把方法都提取出来,形成策略。
首先,定义一个策略接口:
public interface IStrategy {
int calculate();
}
然后呢,定义2个子类都实现上述的接口,并加入不同的算法
public class Straegy1 implements IStrategy{
@Override
public int calculate() {
return (5+5+5+5+5);
}
}
public class Straegy2 implements IStrategy{
@Override
public int calculate() {
return (5*5);
}
}
那么环境角色呢,就是上面的Calculate这个类咯,我们只要稍微的改动一下就可以了,如下:
public class Calculate {
private IStrategy strategy;
public Calculate(IStrategy strategy) {
this.strategy = strategy;
}
public int calculate(){
return strategy.calculate();
}
}
好了,写完了,感觉自己是不是特别棒呢,下面我们就测试一下,到底结果如何呢?测试代码如下:
public class StrategyTest {
public static void main(String[] args) {
Calculate calculate1 = new Calculate(new Straegy1());
System.out.println("Straegy1:apple sum = "+calculate1.calculate());
Calculate calculate2 = new Calculate(new Straegy2());
System.out.println("Straegy2:apple sum = "+calculate2.calculate());
}
}
测试结果如下:Straegy1:apple sum = 25
Straegy2:apple sum = 25
嗯,不错,运行的结果是一致的,看来我们的策略ok了。接下来,有的人会发现,环境角色Calculate完全没必要存在嘛,让系统根据不同的场景执行不同的侧率不就完事了嘛,执行以下代码也是可以的:
public class StrategyTest {
public static void main(String[] args) {
Straegy1 straegy1 = new Straegy1();
System.out.println("Straegy1:apple sum = "+straegy1.calculate());
Straegy2 straegy2 = new Straegy2();
System.out.println("Straegy2:apple sum = "+straegy2.calculate());
}
}
运行结果也是一致的:
Straegy1:apple sum = 25
Straegy2:apple sum = 25
嗯,好像是那么一回事哦。但是仔细的再想想,考虑一下我说的以下几种情况:
1.如果我们在不同的策略中需要初始化一些相同的数据,该怎么办呢?如果我们没有环境角色这个中间体的存在,那我们势必会在方法体里面初始化,但如果我们有了这个中间环境角色,那我们完全可以在环境变量的构造函数中来实现初始化了,这样我们就减少了代码的冗余。
2.如果我们需要改变原有的算法,引进新的参数的时候怎么办呢?一种是重载该算法,增加新的函数接口,另一种是完全废弃掉当前函数接口,重写全新的函数接口。很显然啊,这两种方式的代价都是不可估量的,尤其是只有部分策略需要用到的时候。因此啊,我们用环建角色这个中间体就可以轻松的搞定了。
下面就是我改造的那个策略模式接口,让我们的策略模式也持有环境角色这一变量,这样在不同的策略中,就都可以回调环境角色中的所有的可用函数和变量了。如下:
public interface IStrategy {
int calculate(Calculate calculate);
}
public class Straegy1 implements IStrategy{
@Override
public int calculate(Calculate calculate) {
return (5+5+5+5+5);
}
}
public class Straegy2 implements IStrategy{
@Override
public int calculate(Calculate calculate) {
return (5*5);
}
}
好了,现在需求稍微有点变动,我们需要在Straegy2中知道,这种策略是谁提供的,用author表示。加入没有环境角色的存在,大家应该会去接口和实现接口类中去修改咯,但是,Straegy1的提供者就不乐意了,因为你改动的话他也需要做相应的改动。有了环境角色之后,这一切看起来就都不那么麻烦了,你也不需要去改动策略接口和实现策略接口类Straegy2,只需要改动一下环境角色类Calculate和策略Straegy2就可以了,如下:
public class Calculate {
private IStrategy strategy;
private String author;
public Calculate(IStrategy strategy) {
this.strategy = strategy;
}
public Calculate(IStrategy strategy,String author) {
this.strategy = strategy;
this.author = author;
}
public int calculate(){
return strategy.calculate(this);
}
public String getAuthor() {
return author;
}
}
public class Straegy2 implements IStrategy{
@Override
public int calculate(Calculate calculate) {
System.out.println("Straegy2 author is "+calculate.getAuthor());
return (5*5);
}
}
测试代码如下:
public class StrategyTest {
public static void main(String[] args) {
Calculate calculate1 = new Calculate(new Straegy1());
System.out.println("Straegy1:apple sum = "+calculate1.calculate());
Calculate calculate2 = new Calculate(new Straegy2(),"dandy");
System.out.println("Straegy2:apple sum = "+calculate2.calculate());
}
}
测试结果如下:
Straegy1:apple sum = 25
Straegy2 author is dandy
Straegy2:apple sum = 25
由以上分析可见,策略模式中,各个角色的功能都非常重要,虽然环境角色可以在某些简单的策略模式中不去使用,但是如果无法预测到各个实现策略功能和需求的变化,以及实现灵活性更好的策略模式,在使用策略模式进行架构时,一定要充分利用所有角色的功能。