首页 > 代码库 > 【原】设计模式-策略模式(Strategy Model)
【原】设计模式-策略模式(Strategy Model)
1、概述
在开发过程中常常会遇到类似问题,实现一个功能的时候往往有多种算法/方法(策略),我们可以根据环境的不同来使用不同的算法或策略来实现这一功能。
如在人物比较排序的实现中,我们有时需要把年龄做为比较的标准,或者有时又想将身高作为比较的标准,不同的比较标准也就衍生出了统一个比较目的的不同算法实现,在搜索问题中也是类似,有可能用到二分查找、顺序查找之类。通常较简单直接的思维便是将所有的算法(策略)写成一个类的方法,再通过客户端去调用;也可一将所有的算法全部封装在一个方法中用一堆的if...else...语句来判断。如果需要增加一种算法时,就需要去修改封装算法类的源代码;更换比较排序算法时,又需要去修改客户端代码。在算法类中封装了大量的算法,该类代码较复杂,维护困难;而且将策略包含在客户端,将导致客户端的程序庞大难以维护。
案例:出行旅游:出行旅游时,我们有以下几个策略可供选择:自行车、汽车、火车、飞机等,不同的方式,单都是去实现旅行这一个目的,选择策略的依据是时间、金钱、方便程度(对应到工程中就是需求的环境)。
2、目的
策略模式的目的在于:使算法和对象分离开来,能让算法独立于对象去变化。
核心思想其实是利用了面向对象编程多态的使用。
3、适用场景
当存在一下情况时使用Strategy模式:
1)许多类实现统一目的,仅方式不同。“策略”提供了一种用多个行为中的一种来配置类的实现的方法,及一个系统可以动态的在多个算法中选择其中一种;
2)需要同一中算法的不同变体。如:在比较对象时,采用的比较算法的不同,有可能需要去比较对象的成员变量;
3)一个类或者方法中定义了多种行为,并且这些行为以多个判断语句来相互切换。可将相关的条件分支移入各自的Strategy类中去实现。
4)算法的封装。通过策略模式向使用算法的客户隐藏算法的具体实现。
4、结构与组成
策略模式的结构主要分类三个部分:
抽象策略类(Strategy):定义所有实现算法的公共接口,Context直接使用接口调用ConcreteStrategy的具体算法。
具体策略类(ConcreteStrategy):实现具体的算法,每个具体的算法类必须实现Strategy接口。
环境类(Context):具体算法的使用类,需要用指定的一个ConcreteStrategy来配置。
4、实现
一个班级的若干个学生,对他们进行排序分别按照名字、年龄、id排序(正序和倒序两种方式),如年龄和名字重复,则使用id进行升序排序。
1 package com.cnblogs.vicentzh.strategymodel; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.Comparator; 6 import java.util.Iterator; 7 import java.util.List; 8 9 public class StrategyModel 10 { 11 /** 12 * @Describe 客户端程序 13 * @param args 14 */ 15 public static void main(String[] args) 16 { 17 Student p1 = new Student("Tom",1,20); 18 Student p2 = new Student("Tonny",2,50); 19 Student p3 = new Student("Tom",5,30); 20 Student p4 = new Student("John",8,10); 21 Student p5 = new Student("Susan",9,15); 22 23 List<Student> students = new ArrayList<Student>(); 24 students.add(p1); 25 students.add(p2); 26 students.add(p3); 27 students.add(p4); 28 students.add(p5); 29 30 Context env = new Context(); 31 32 //正序排列 33 UpNameSort uns = new UpNameSort(); 34 env.setSortStrategy(uns); 35 env.sort(students); 36 37 for (Iterator<Student> iter=students.iterator(); iter.hasNext();) 38 { 39 Student student = iter.next(); 40 System.out.println("id: " + student.getId() + ", name: " + student.getName() 41 + ", age:" + student.getAge()); 42 } 43 System.out.println("-----------------------"); 44 45 //倒序排列 46 DownNameSort dns = new DownNameSort(); 47 env.setSortStrategy(dns); 48 env.sort(students); 49 50 for (Iterator<Student> iter=students.iterator(); iter.hasNext();) 51 { 52 Student student = iter.next(); 53 System.out.println("id: " + student.getId() + ", name: " + student.getName() 54 + ", age:" + student.getAge()); 55 } 56 57 } 58 } 59 60 61 //需要用到的具体实例类 62 class Student 63 { 64 private String name; 65 private int age; 66 private int id; 67 68 public Student(String name, int age, int id) 69 { 70 this.name = name; 71 this.age = age; 72 this.id = id; 73 } 74 75 public String getName() 76 { 77 return name; 78 } 79 public int getAge() 80 { 81 return age; 82 } 83 public int getId() 84 { 85 return id; 86 } 87 } 88 89 90 //抽象策略类(Strategy),即策略接口 91 interface SortStrategy 92 { 93 public void sortStudent(List<Student> students); 94 } 95 96 97 //具体策略类(ConcreteStrategy),即具体正序算法实现类 98 class UpNameSort implements SortStrategy,Comparator<Student> 99 {100 @Override101 public void sortStudent(List<Student> students)102 {103 Collections.sort(students, this);104 }105 106 @Override107 public int compare(Student o1, Student o2)108 {109 int result = o1.getName().compareTo(o2.getName());110 if(0==result)111 {112 return o1.getId() - o2.getId();113 }114 return result;115 }116 }117 118 //具体策略类(ConcreteStrategy),即具体倒序算法实现类119 class DownNameSort implements SortStrategy, Comparator<Student>120 {121 @Override122 public void sortStudent(List<Student> students)123 {124 Collections.sort(students, this);125 126 }127 128 @Override129 public int compare(Student o1, Student o2)130 {131 int result = o2.getName().compareTo(o1.getName());132 if(0==result)133 {134 return o1.getId() - o2.getId();135 }136 return result;137 }138 }139 140 //使用环境类(Context)141 //环境类根据接收到客户端具体的策略来对对象进行使用,同样也能用setSortStrategy方法142 //随时根据客户端的需求去改变策略算法,并且不影响对象。143 class Context144 {145 private SortStrategy concreteStrategy; //使用策略配置环境类146 147 public Context(SortStrategy conSortStrategy)148 {149 this.concreteStrategy = conSortStrategy;150 }151 152 public Context()153 {154 155 }156 157 //可随意定制化具体策略158 public void setSortStrategy(SortStrategy conSortStrategy)159 {160 this.concreteStrategy = conSortStrategy;161 }162 163 //使用具体的策略(concreteStrategy)对对象进行操作164 public void sort(List<Student> students)165 {166 concreteStrategy.sortStudent(students);167 }168 }
5、优缺点
Strategy模式的优点:
1)Strategy类将具体的算法进行抽象,为Context类提供了一系列可重用的算法或行为,同时屏蔽了底层算法实现的细节,同样也提高了代码的可重用性。
2)通过Strategy模式,将具体策略的实现与应用的对象隔离开来,实现行为与对象的解耦;这样能是应用对象动态便捷的动态改变行为,使得算法易于切换、易于理解、易于扩展;
3)消除了大量if...else...代码的冗余性和复杂性,以行为封装的形式使代码的逻辑表达更为清晰。
Strategy模式的缺点:
1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类: 模式的潜在缺点就是一个客户要选择一个合适的Strategy就必须知道这些Strategy到底有何不同。此时可能不得不向客户暴露具体的实现问题。
2)Strategy和Context之间的通信开销 :无论各个ConcreteStrategy实现的算法是简单还是复杂, 它们都共享Strategy定义的接口。因此很可能某些 ConcreteStrategy不会都用到所有通过这个接口传递给它们的信息;简单的 ConcreteStrategy可能不使用其中的任何信息!这就意味着有时Context会创建和初始化一些永远不会用到的参数。
3)策略模式将造成产生很多策略类:可以通过使用享元模式在一定程度上减少对象的数量。 增加了对象的数目 Strategy增加了一个应用中的对象的数目。
6、总结分析
1)策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的实现和算法的使用对象解耦,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
2)策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“换代”和“退休”的方便。
3)在策略模式中,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。
作者:vincentzh
出处:http://www.cnblogs.com/vincentzh/
本文以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,非商业用途!
【原】设计模式-策略模式(Strategy Model)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。