策略模式(strategy pattern)
策略模式在java集合中的TreeSet和TreeMap中得到了很好的应用,我们可以实现Comparator接口实现Compareto()方法来定义自己的排序规则,然后通过TreeSet,TreeMap构造方法传入实现该接口的实例,map中的顺序就会是我们自定义的顺序。我们可以完全定义自己的规则,用之极为方便。那么,什么是策略模式呢?
策略模式定义:定义一组算法,将每个算法都封装起来,并且使它们之间可以转换。策略模式使这些算法在客户端调用时能够互不影响的变化。
策略模式组成:
1.抽象的策略角色:策略类,通常由一个抽象类或者接口实现。
2.具体的策略角色:包装了相关的算法和行为。
3.环境角色:持有一个策略类的引用,以便最终给客户端调用。
策略模式的设计原则:
1. 封装变化
2.使用接口编程
策略模式的实现:
1.将每一组算法封装到具有共同接口的独立类中,这样不同的策略可以相互替换
2.算法可以在不影响客户端的情况下发生变化,把行为和环境分开。
3.环境类负责维持和查询行为类,各种算法在具体策略中提供
看文字看蒙了,举一个具体的例子吧,举什么例子呢?想到我们数据结构中的各种排序,什么冒泡排序,快速排序,堆排序...,他们完成的功能都是一样的,只是排序算法不同而已。我们就可以看成是排序的不同策略。
首先定义我们的抽象策略:
/**
* 抽象的策略类
* @author
*
*/
public interface Strategy { public void sort(int[] array);
}
定义具体的策略,这里实现了三种策略,分别是快速排序,堆排序,归并排序。
快速排序策略代码:
public class QuickSort implements Strategy{ @Override
public void sort(int[] array) {
qpSort(array,0,array.length - 1);
} private void qpSort(int array[], int low, int high) {
int pos = qkPass(array, low, high); //产生中间第一个确定的数 if (low < high) {
qpSort(array, low, pos - 1);//左边
qpSort(array, pos + 1, high);//右边
}
} private int qkPass(int a[], int low, int high) {
int x = a[low]; while (low < high) { while (low < high && a[high] > x) {
high--;
}
if (low < high) {
a[low] = a[high];
low++;
}
while (low < high && a[low] < x) {
low++;
}
if (low < high) {
a[high] = a[low];
high--;
}
}
a[low] = x; return low;
} }
堆排序策略代码:
public class HeapSort implements Strategy { @Override
public void sort(int[] array) {
heapSort(array,array.length);
} private void heapSort(int a[], int length) { crtHeap(a, length); // 创建大根堆 for (int i = length - 1; i > 0; i--) { int b = a[0]; a[0] = a[i]; // 堆顶跟堆尾互换 a[i] = b; sift(a, 0, i - 1); // 使得r[0...i-1]变成堆
}
} /**
* 建立初堆
*
* @param a
* 为带排序的数组
* @param length
* 为数组长度
*/
private void crtHeap(int a[], int length) { int n = length - 1; // 建出堆,从第 n/2 个记录开始进行堆筛选
for (int i = n / 2; i >= 0; i--) { sift(a, i, n);
}
} /**
*
* @param r
* 数组
* @param k
* 表示以r[k]为根的完全二叉树,调整r[k],使得r[k...m]满足大根堆的性质
* @param m
* 堆尾元素下标
*/
private void sift(int r[], int k, int m) { int temp = r[k]; // 暂存根记录 int i = k; // 记录初始根的下标 int j = i * 2 + 1; // 根的左孩子,因为下标从0开始 while (j <= m) {
// 如果存在右子树,且右子树根的关键字大,则沿右分支筛选,否则沿左分支筛选。因为目的是找一个最大的元素
if (j < m && r[j] < r[j + 1]) {
j = j + 1;
} if (temp >= r[j]) {
break; // 结束筛选
}
else {
r[i] = r[j]; // 上移
i = j; // 从新定义根下标
j = j * 2 + 1;// 继续筛选
}
} r[i] = temp; // 将r[k]移动到适当的位置
} }
归并排序策略代码:
public class MergeSort implements Strategy{ @Override
public void sort(int[] array) {
int[] temp = new int[array.length];
mSort(array,0,array.length - 1, temp);
} /**
*
* @param r1 等待排序数组
* @param low
* @param high
* @param r3 将r1排序后的结果放在r3中 r1[low...high],r3[low...high]
*/
private void mSort(int r1[],int low,int high, int r3[]){ if(low < high)
{
int mid = (low + high) /2; //归并排序中 拆,合要一起进行
mSort(r1,low,mid,r3); mSort(r1,mid+1,high,r3); merge(r1,low, mid, high, r3);
} } private void merge(int r1[],int low, int mid, int high, int r2[]){ int i = low;
int j = mid + 1;
int k = 0; while(i <=mid && j <= high){ if(r1[i] <= r1[j]){
r2[k] = r1[i];
i++;
}
else{
r2[k] = r1[j];
j++;
} k++;
} while(i <= mid){
r2[k] = r1[i];
i++;
k++;
} while(j <= high){
r2[k] = r1[j];
j++;
k++;
} for(int m = 0; m < k;m++){
r1[low + m] = r2[m];
}
} }
定义环境类:
public class Environment { private Strategy strategy; //策略类的引用 public Environment(Strategy strategy){
this.strategy = strategy;
} //用于设置不同的策略
public void setStrategy(Strategy strategy){
this.strategy = strategy;
} //实现排序的功能
public void sort(int array[]){
strategy.sort(array);
} }
最后定义客户端类:
public class Client { public static void main(String[] args) { int[] array1 = new int[]{48,62,35,77,55,14,35,98};
int[] array2 = new int[]{48,62,35,77,55,14,35,98};
int[] array3 = new int[]{48,62,35,77,55,14,35,98}; //使用堆排序策略
Environment env = new Environment(new HeapSort()); env.sort(array1);
System.out.println("使用堆排序array1:");
print(array1); //使用快速排序策略
env.setStrategy(new QuickSort());
env.sort(array2);
System.out.println("使用快速排序array2:");
print(array2); //使用归并排序策略
env.setStrategy(new MergeSort());
env.sort(array3);
System.out.println("使用归并排序array3:");
print(array3); } static void print(int[] array){
for(int i = 0; i < array.length; i++){
System.out.print(array[i] + "\t");
}
System.out.println();
System.out.println("---------------------------------");
}
}
运行结果如下所示:
我们使用不同的排序策略分别对三个数组排序的功能已经实现了,程序非常灵活,我们想用什么策略来实现排序可以自己决定(通过environment.serStrategy(XXX)方法)。
程序中Environment类根本不知道也不用管排序到底是怎么实现的,它只是持有一个具体策略类的引用,然后调用具体策略类的方法。
策略模式用着很方便,但是本身也有缺点:
1.客户端必须知道所有的策略类,并自行决定使用哪种策略类。
2.造成很多的策略类,每一个不同的策略都需要一个策略类来实现。
对于第一点很明显,我们客户端(client类)在使用策略时必须知道具体的策略类是什么,environment.serStrategy(XXX)方法也需要知道。
对于第二点,定义了3中策略,就有3个策略类,如果策略很多的话,类也会很多。
参考资料:圣思园教学视频
策略模式(strategy pattern)的更多相关文章
- 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)
在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了“工厂模式”.“策略模式”.“状态模式”等.当然在重构时,有的地 ...
- 设计模式 - 策略模式(Strategy Pattern) 具体解释
策略模式(Strategy Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权全 ...
- HeadFirst设计模式读书笔记(1)-策略模式(Strategy Pattern)
策略模式(Strategy Pattern): 定义了了算法簇,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户端. 第一个设计原则:找出应用中可能需要变化之处,把他们独立 ...
- 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)
原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...
- 反馈法学习设计模式(一)——策略模式Strategy Pattern
简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例.便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习. 首先我们通过练习,逐步写出符合 ...
- 8.6 GOF设计模式四: 策略模式… Strategy Pattern
策略模式… Strategy Pattern 在POS系统中,有时需要实行价格优惠, 该如何处理? 对普通客户或新客户报全价 对老客户统一折扣5% 对大客户统一折扣10% 注:课件 ...
- 二十四种设计模式:策略模式(Strategy Pattern)
策略模式(Strategy Pattern) 介绍定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法的变化可独立于使用它的客户. 示例有一个Message实体类,对它的操作有 ...
- 设计模式系列之策略模式(Strategy Pattern)
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换. 主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护. 何时使用:一个系统有许多许多类,而区分它 ...
- 十一个行为模式之策略模式(Strategy Pattern)
定义: 定义一系列的算法,将每一个算法封装起来,并使它们之间可以相互替换,让算法具有可扩展性和对立性. 结构图: Context:环境类,算法的使用者.对外提供了算法使用的接口,并且持有一个抽象算法类 ...
随机推荐
- [转]权限问题导致Nginx 403 Forbidden错误的解决方法
权限问题导致Nginx 403 Forbidden错误的解决方法 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-08-22 这篇文章主要介绍了权限问题导致Nginx 403 F ...
- MySQL Innodb数据库性能实践——热点数据性能
摘要: 对于大部分的应用来说,都存在热点数据的访问,即:某些数据在一定时间内的访问频率要远远高于其它数据. 常见的热点数据有“最新的新闻”.“最热门的新闻”.“下载量最大”的电影等. 为了了解MySQ ...
- 如何通过WPS 2013 API 将Office(Word、Excel和PPT)文件转PDF文件
1. 描述 PDF 文件是一种便携文件格式,是由Adobe公司所开发的独特的跨平台文件格式.PDF文件以PostScript语言图象模型为基础,无论在哪种打印机上都可保证精确的颜色和准确的打印效果,即 ...
- C#图像处理
网站中,对用户图片上传处理是很有必要的.对于一些常用的处理,对图片各种形式的压缩,各种形式的水印. 1.裁剪正方形头像方法 /// <summary> /// 正方型裁剪 /// 以图片中 ...
- 为了体验 ILS 在Win2012R2 Hyper-V上安装Windows 2000 AdvSer
Win2012 R2 Hyper-V 的集成服务包已不支持Windows 2000 先安装SP4.IE6.更新汇总包,再来安装这个. 安装完成后,会有几个未知设备,直接禁用就可以了. 开启Window ...
- 编写更好的jQuery代码
这是一篇关于jQuery的文章,写到这里给初学者一些建议. 现在已经有很多文章讨论jQuery和JavaScript的性能问题,然而,在这篇文章中我计划总结一些提升速度的技巧和一些我自己的建议来改善你 ...
- web.py学习心得
1.注意判断数字时,如果是get传递的参数,一定要用int转换.不然出错. 2.$var 定义时,冒号后的内容不是python内容,需加上$符号.如$var naviId:$naviId. 3.各个模 ...
- 彻底解决rman恢复碰到ora-01152错
说说碰到这个问题的背景.使用NBU调脚本对oracle进行备份.脚本如下:RUN {ALLOCATE CHANNEL ch00 TYPE 'SBT_TAPE';ALLOCATE CHANNEL ch0 ...
- HDU 4003 [树][贪心][背包]
/* 大连热身A题 不要低头,不要放弃,不要气馁,不要慌张 题意: 给一棵树,每条边上有权值.给一个起点,放置n个机器人,要求使得任意一个节点至少被一个机器人经过. 每个机器人经过某条边时的代价为这条 ...
- LeedCde 题解目录
1. Longest Palindromic Substring ( 最长回文子串 ) 2. Median of Two Sorted Arrays (两个排序数组的中位数) 3. Sqrt(x) 4 ...