开发文章

设计模式系列--策略模式

什么是策略模式

在前面的博文中,小编主要向小伙伴介绍了组合模式,今天这篇博文,我们继续来学习设计模式的相关知识,今天和小伙伴们见面的是策略模式,策略模式英文名字叫Strategy,策略模式属于行为模式的一种,她对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定,策略模式主要用来平滑的处理算法的切换。

策略模式结构图

我们来看一下策略的结构图,如下所示:

策略的结构图.png

对上述结构图进行简单的解释说明:

        a、将所有的算法都抽象成了Strategy,可以将算法分离出来并且进行更换。
        b、Context 中含有对Strategy的引用。
        c、通过contextInterface(),进行对算法的使用。

         从上面的结构图中,可以看出这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少各种算法类与使用算法类之间的耦合。换句话说,策略模式并不将算法固定在具体的某个类中,而是将算法独立出来,可根据需要替换算法。例如:Context中含有对 Straategy的引用。这里还用到了依赖倒转和里斯代换原则,即Context依赖于抽象,而没有依赖具体的子类,并且,子类可以替换父类。

策略模式简单应用demo

接着,我们通过一个简单的demo来了解一下策略模式是如何在实际中加以应用的,新建java项目Strategy,新建类MainClass,新建接口Strategy,编写接口里面的代码部分,如下所示:

复制内容到剪贴板
  1. public interface Strategy {      
  2.     //加密      
  3.     public void encrypt();      
  4.           
  5. }    

 

新建类MD5Strategy,实现接口Strategy,编写相关代码,如下所示:

复制内容到剪贴板
  1. public class MD5Strategy implements Strategy {      
  2.       
  3.     @Override      
  4.     public void encrypt() {      
  5.         System.out.println("执行MD5加密");      
  6.       
  7.     }      
  8.       
  9. }      

新建类MDSStrategy,实现接口Strategy,编写相关代码,如下所示:

复制内容到剪贴板
  1. public class MDSStrategy implements Strategy {      
  2.       
  3.     @Override      
  4.     public void encrypt() {      
  5.         System.out.println("执行MDS加密");      
  6.       
  7.     }      
  8.       
  9. }      

如果我们不使用策略模式,我们会在MainClass里面如何编写代码呢?如下所示:

复制内容到剪贴板
  1. public class MainClass {      
  2.     public static void main(String[] args){      
  3.         Strategy stra =  new MD5Strategy();      
  4.         stra.encrypt();      
  5.     }      
  6. }    

如果要执行MDSS的方法,我们可以对MainClass中的代码部分进行修改,如下所示:

复制内容到剪贴板
  1. public class MainClass {      
  2.     public static void main(String[] args){      
  3.         Strategy stra =  new MDSStrategy();      
  4.         stra.encrypt();      
  5.     }      
  6. }      

 

通过这种方式,可以实现动态的转变,我们只需要在客户端进行改变即可,但是这个不符合策略模式,通过结构图,我们可以看到有一个Context,可以理解成是一个工厂,创建Context类,并编写相关代码,如下所示:

复制内容到剪贴板
  1. public class Context {      
  2.     private Strategy strategy;      
  3.     public Context(Strategy strategy){      
  4.         this.strategy = strategy;      
  5.     }      
  6.           
  7.     public void encrypt(){      
  8.         this.strategy.encrypt();      
  9.     }      
  10.       
  11. }      

编写客户端的代码,如下所示:

复制内容到剪贴板
  1. public class MainClass {      
  2.     public static void main(String[] args){      
  3. //      Strategy stra =  new MDSStrategy();      
  4. //      stra.encrypt();      
  5.               
  6.         Context context = new Context(new MD5Strategy());      
  7.         context.encrypt();      
  8.     }      
  9. }      

执行MDSS,修改客户端代码如下所示:

复制内容到剪贴板
  1. public class MainClass {      
  2.     public static void main(String[] args){      
  3. //      Strategy stra =  new MDSStrategy();      
  4. //      stra.encrypt();      
  5.               
  6.         Context context = new Context(new MDSStrategy());      
  7.         context.encrypt();      
  8.     }      
  9. }      

通过这两种方式的实现,经过对比我们可以发现,我们直接通过Context进行调用,我们可以把Strategy看成是一个抽象的接口,我们再来举一个简单的例子,帮助我们进一步加深对策略模式的理解,新建包Strategy,新建类MainClass,新建接口Strategy,编写相关代码如下所示:

复制内容到剪贴板
  1. package Strategy;      
  2.       
  3. public interface Strategy {      
  4.     public double cost(double num);      
  5. }      

新建类StrategyA实现Strategy,编写相关代码,如下所示:

复制内容到剪贴板
  1. package Strategy;      
  2.       
  3. public class StrategyA implements Strategy {      
  4.       
  5.     @Override      
  6.     public double cost(double num) {      
  7.         return num*0.8;      
  8.     }      
  9.       
  10. }      

新建类Context,编写相关代码,如下所示:

复制内容到剪贴板
  1. package Strategy;      
  2.       
  3. public class Context {      
  4.     private Strategy strategy;      
  5.           
  6.     public Context (Strategy strategy){      
  7.         this.strategy=strategy;      
  8.     }      
  9.           
  10.     public double cost(double num){      
  11.         return this.strategy.cost(num);      
  12.     }      
  13.       
  14. }      

新建MainClass,编写相关代码,如下所示:

复制内容到剪贴板
  1. package Strategy;      
  2.       
  3. public class MainClass {      
  4.     public static void main(String[] args) {      
  5.         double num = 200;      
  6.         Context context = new Context(new StrategyA());      
  7.         double newNum = context.cost(num);      
  8.         System.out.println("实际付款"+newNum+"元");      
  9.     }      
  10.       
  11. }      

这个时候,商家改变策略,不打八折了,这个时候改成满200返50,我们该如何实现呢?新建类StrategyB,实现Strategy,编写相关代码,如下所示:

复制内容到剪贴板
  1. package Strategy;      
  2.       
  3. public class StrategyB implements Strategy {      
  4.       
  5.     @Override      
  6.     public double cost(double num) {      
  7.         if(num >= 200){      
  8.             return num-50;      
  9.         }      
  10.         return num;      
  11.     }      
  12.       
  13. }     

编写MainClass中的代码部分,如下所示:

复制内容到剪贴板
  1. package Strategy;      
  2.       
  3. public class MainClass {      
  4.     public static void main(String[] args) {      
  5.         double num = 200;      
  6.         Context context = new Context(new StrategyB());      
  7.         double newNum = context.cost(num);      
  8.         System.out.println("实际付款"+newNum+"元");      
  9.     }      
  10. }      

这样,我们直接实现接口,写一个方法就可以了,接着,我们来看一下策略模式的优缺点:

优点:

a、策略模式提供了管理相关的算法族的办法,策略类的等级结构定义了一个算法或行为族,恰当使用继承可以公共的代码移到父类里面,从而避免重复的代码。

b、策略模式提供了可以替换继承关系的办法,继承可以处理多种算法和行为,如果不使用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法和行为,但是,这样一来算法或行为的使用者就和算法或行为本身混在一起,决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再单独演化,继承使得动态改变算法或行为变得不可能。

c、使用策略模式可以避免使用多重条件转移语句,多重转移语句不易维护,他把采用哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。

缺点:

a、客户端必须知道所有的策略类,并执行决定使用哪一个策略类,这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类,换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
b、策略模式造成很多的策略类,有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用,换言之,可以使用享元模式来减少对象的数量。

该文主要简单的介绍了策略模式,分别从什么是策略模式、策略模式的结构图、策略模式简单应用demo、策略模式的优缺点四个方面对策略模式进行了简单的介绍,策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。在策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略角色。策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。

感谢 丁国华 支持 磐实编程网 原文地址:
blog.csdn.net/u010850027/article/details/52825019

文章信息

发布时间:2018-03-24

作者:丁国华

发布者:aquwcw

浏览次数: