从诸葛亮的三个锦囊妙计谈策略模式
话说当年东吴孙权为刘备借走了荆州不还而耿耿于怀,却不料甘夫人去世,周郎顿时计上心来,让孙权将其妹嫁与刘备,骗刘备来东吴完婚。刘备又不是傻子,当然知道其中的猫腻,当即表态:打死也不去。诸葛亮却说无妨,当下给了赵云三个锦囊妙计,让他陪刘备去东吴完婚……最后的结果大家都知道,赵云在恰当的时候一一打开三个锦囊妙计,从而将危机一一化解。周瑜只落了个“周郎妙计安天下,赔了夫人又折兵”的笑柄。
这个故事,我们感兴趣的是三个锦囊妙计。诸葛亮一定是运用策略模式的高手,我们想啊:诸葛亮为什么要这么麻烦,做三个锦囊,他完全可以只做一个锦囊,将这三个妙计都写在它上面。可他没有这么做,而是正确的运用了策略模式做了三个锦囊。这样做的好处十分明显:诸葛亮一个锦囊写一个妙计,他的思路十分清晰,不会三个计策相互混乱。而赵云看妙计的时候也十分方便,什么时候看哪个妙计,使用十分方便,如果三个妙计混在一起,他就没这么方便了。
现在看来,这个故事正包含了策略模式的解决问题的思路:解决某一问题有多种方法或算法,如诸葛亮给了三个妙计,类的提供者要将这多种方法或算法独立开来,如诸葛亮将三个妙计分三个锦囊装,类的使用者,如赵云,在相应的条件,如故事中的恰当时间,使用相应的方法或算法。
前面我们说过命令模式,命令模式是对行为的封装;策略模式其实跟它的解决思路一样,是对算法的封装。当然,它们都一样的拥有同一个接口。
下面我们以一些例子来详细的说一说策略模式。
首先的一个例子是我们对数组的排序,对数组的排序有很多算法,我们想做一个由用户指定一个整形数组和对它排序的算法,我们给出结果这样一个方法,我们可以这样做:

public int[] sort(int[] inArray,String type)

{
if(type.equals(“a”))
{
int k = 0;
for(int i=0;i<inArray.length;i++)
{
for(int j=i+1;j<inArray.length;j++)
{

if(inArray[i]> inArray[j])

{

k = inArray[i];

inArray[i] = inArray[j];

inArray[j] = k;

}
}
}
}
else if(type.equals(“b”))
{
int k = 0;
for(int i=0;i< inArray.length;i++)
{

for(int j=0;j< inArray.length-i-1;j++)

{
if(inArray [j]> inArray [j+1])
{
k = inArray [j];
inArray [j] = inArray [j+1];
inArray [j+1] = k;
}
}
}
}
}
一看上面的代码,大家就觉得问题很多:第一,所有的算法都搅和在一起,不满足单一职责原则。第二,依赖细节,不满足依赖颠倒原则。第三,扩展性不好,如果要增加一个新的算法,需要对该方法进行改动。
下面我们来看看策略模式的解决思路。
首先是对所有的算法抽象一个接口,这是为了满足扩展性的基本条件,几乎所有的模式都要以接口为基础:
public interface SortAlgorithm
{

public void sort(int[] inArr);

}
然后是各个算法的具体实现,它们实现了SortAlgorithm接口,完成了对关注点的分离,满足单一职责原则:

public class SortOne implements SortAlgorithm

{

public void sort(int[] inArr)

{
int k = 0;
for(int i=0;i<inArr.length;i++)
{
for(int j=i+1;j<inArr.length;j++)
{

if(inArr[i]> inArr[j])

{

k = inArr[i];

inArr[i] = inArr[j];

inArr[j] = k;

}
}
}
}
}

public class SortTwo implements SortAlgorithm

{

public void sort(int[] inArr)

{
int k = 0;
for(int j=0;j< inArr.length-i-1;j++)
{

if(inArr[j]> inArr[j+1])

{
k = inArr[j];
inArr[j] = inArr[j+1];
inArr[j+1] = k;
}
}
}
}
然后我们来看客户端的调用:

public int[] sort(int[] inArray,String type)

{
SortAlgorithm sa;
if(type.equals(“a”))
{

sa = new SortOne();

}

else if(type.equals(“b”))

{

sa = new SrotTwo();

}
else
{
……
}
sa.sort(inArray);
}
上面我们就完成了策略模式对该问题的解决,满足了单一职责原则;有了一定的扩展性,如果新增一个算法的话,去实现SortAlgorithm接口就可以了。
当然,我们在客户端代码可以看到,策略模式依然没有完全去掉客户端对具体实现类的依赖,这使得我们增加一个新的算法以后,仍然需要对客户端进行修改。所以策略模式和命令模式一样,只是初步增加了一定的扩展性。如果要完全去掉客户端对具体类的依赖,可以结合工厂模式来对该问题作进一步优化,具体做法大家可以自己做,这里不再讲述。
所谓策略模式,简单说来就是对算法的封装。在实际的编码过程中,我们会遇到各种各种的选择算法的问题,这时候就可以使用策略模式了,下面以一个例子来作为本文的结束。
假设我们有一个POJO类:Employee,里面存储了很多用户的信息,如下:
public class Employee
{

private int id;

private String name;

private double servedYears;

……

public void setId(int id)

{
this.id = id;
}
public int getId()
{
return this.id;
}

public void setName(String name)

{
this.name = name;
}
public String getName()
{
return this.name;
}

public void setServedYears(double servedYears)

{
this.servedYears = servedYears;
}

public double getServedYears()

{
return this.servedYears;
}
……
}
现在我们有一个关于Employee的数组,需要对数组进行排序,我们知道该使用Arrays.sort()对该数组进行排序,但是在使用该方法的时候,我们首先要实现Comparator接口,如下:

Arrays.sort(emps,new Comparator(){

Public int compare(Object o1,Object o2)

{

return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();

}
});
上面实现了一个对POJO对象的排序过程,现在的问题是我们分别需要对Employee类的id、name和servedYears为索引进行排序。我们可以看出,这明显是多个算法的问题,可以使用策略模式来解决问题:
以id为索引的比较器:

public class IdComparator implements Comparator

{

Public int compare(Object o1,Object o2)

{

return ((Employee)o1).getId()-((Employee)o2).getId();

}
}
以name为索引的比较器:

public class NameComparator implements Comparator

{

Public int compare(Object o1,Object o2)

{

return ((Employee)o1).getName()-((Employee)o2).getName();

}
}
以servedYears为索引的比较器:

public class ServedYearsComparator implements Comparator

{

Public int compare(Object o1,Object o2)

{

return ((Employee)o1).getservedYears()-((Employee)o2).getServedYears();

}
}
然后,我们做一个工厂来获取具体的比较器:
public class Factory
{

public static Comparator getInstance(String type)

{
if(type.equals(“id”))
{
return new IdComparator();
}
else if(type.equals(“name”))
{
return new NameComparator();
}
else
{
return ServedYearsComparator();
}
}
}
那么我们就可以对客户端进行编码了:

public void sort(Employee[] emps,String type)

{
Arrays.sort(emps,Factory.getInstance(type));
}
我们可以看到,结合了工厂模式的策略模式的确使多算法的问题得到了很好的解决:抽取了各个算法来单独关注,满足了单一职责原则;满足了依赖颠倒原则,有了很好的扩展性。等等。
还等什么呢?赶快到实践中去灵活运用这些模式吧!

从诸葛亮的三个锦囊妙计谈策略模式相关推荐

  1. Head First设计模式读书笔记——策略模式

    问题描述: 目前的任务是实现一个FPS类游戏的各种角色(友军.敌军.平民和狗.猫.鸭子等动物)以及他们的各种行为(攻击.游泳等). 设计方案一 很简单,只要实现一个角色超类,将角色的各种行为放入超类中 ...

  2. springboot 文件上传 各种姿势 解锁,策略模式简单运用

    总结:从文件上传谈 策略模式运用 ,虚拟路径配置,纸上得来终觉浅,绝知此事要躬行. 单文件,多文件,base64 几种上传方式 .具体细节参考我的代码库 https://gitee.com/www.l ...

  3. 一文搞懂策略模式(优化策略模式完全消除if else)

    注重版权,转载请注明原作者和原文链接 作者:码农BookSea 原文链接:https://blog.csdn.net/bookssea/article/details/117043820?spm=10 ...

  4. Java设计模式——策略模式(解决满屏的if/else)

    一.业务场景 项目需要对接支付系统,根据不同客户类型会有不同的支付方式,比如:支付宝.微信.银联.云闪付等等其他第三方支付平台,这个时候策略模式就大展身手了. 传统的if/else/switch 等等 ...

  5. 设计模式之Strategy策略模式

    文章目录 前言 一.Strategy策略模式 二.策略模式原则 三.使用场景 1.先做比较练习 2.为一组对象排序 3.使用Lambda表达式的方式 前言 本人对于设计模式的学习,仅供参考! 一.St ...

  6. 设计模式 | 挑战策略模式

    theme: vue-pro 这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战 一.概念 策略模式(Strategy Pattern)作为一种软件设计模式,指对象有某个行为,但是在不同的场景 ...

  7. 设计模式:策略模式(C++)【诸葛亮的锦囊妙计】

    序言 今天带领大家一起来学习下策略模式,看到策略二字,就让笔者想到了谋略,想到了三国,那个谋士如云.英雄辈出的年代.遥想公瑾当年,小乔初嫁了,雄姿英发.咳咳,扯回来.我们所说的策略 ,从字面意思就是一 ...

  8. 锦囊妙计——策略模式

    策略模式 ​ Strategy Pattern:策略模式是GoF23中设计模式中属于行为型设计模式的一种. ​ 策略模式的关键点就在于策略两字,策略是一种方法,一种方式,一种计策.用术语来讲的话,可以 ...

  9. else 策略模式去掉if_设计模式(三)——简单的状态模式代替if-else

    博主将会针对Java面试题写一组文章,包括J2ee,SQL,主流Web框架,中间件等面试过程中面试官经常问的问题,欢迎大家关注.一起学习,一起成长. 前言 大多数开发人员现在还在使用if else的过 ...

最新文章

  1. ubuntu mysql 改密码_tpcc-mysql 压力测试
  2. httpClient多线程问题
  3. go使用反射reflect获取变量类型
  4. 参数校验放在controller还是service_@Validated校验的实践
  5. 腾腾流氓,云云更流氓(问微信怎样接入支付宝支付),手贱的赶紧点,你会感谢我的...
  6. 用python写helloworld_Python Helloworld程序简单实现
  7. 华为服务器麒麟系统,麒麟云服务器
  8. 关于JAVA小程序完整打包过程
  9. vue H5移动端项目 真机测试配置
  10. 移动H5 iPhone audio没有声音(声音不同步)问题的解决方式
  11. c语言拆礼盒,拆礼盒、个人中心功能优化
  12. Fortran之format输出
  13. python操作服务器(二)
  14. 会议通知html页面,【会议通知H5】送你最新会议邀请函H5教程,请点击查收!
  15. 识别电路板上贴片电阻型号0805 0402 0603 1206封装信息
  16. nodejs(五)node引入核心模块fs
  17. python输出无空格,python 2.7.5+打印列表后面没有空格的逗号
  18. 《Cisco IPv6网络实现技术(修订版)》一1.5 IPv5
  19. 浅谈供应链管理SCM的五大功能
  20. Java应用系统监控看这篇就够了

热门文章

  1. T400 Windows7下面迅盘的启用
  2. “碳中和”研究为什么需要气象数据
  3. java visibility_CSS visibility属性
  4. 谁是IPFS中国区“奶王”?IPFS.FUND周欢当仁不让
  5. 华为儿童手表可以升级鸿蒙吗,华为儿童手表 4X功能更新,儿童版微信上线
  6. SAP所有模块用户出口(转)
  7. python爬取斗鱼图片
  8. CCF-集合竞价(开盘价定为买价,1e8*5000--long long)
  9. 【paper】latex使用algorithm工具包实现伪代码排版
  10. Javascript ES6(一)