《二 》策略模式

  相信很多人都玩过魔兽世界这款游戏,它里面的战士有三种姿态:防御、狂暴、战斗,那么在不同的场景下我们需要使用不通的姿态,比如当MT抗怪就需要使用防御姿态,战场需要使用战斗姿态,而输出可能就要使用到狂暴姿态。那么在Java程序中使用硬编码的方式实现如下:
//战士抽象类
public abstract class Warrior {public abstract void changeStance();
}
//狂暴战
public class FuryWarrior extends Warrior{@Overridepublic void changeStance() {System.out.println("切换至狂暴姿态");}}
//防战
public class TankWarrior extends Warrior {@Overridepublic void changeStance() {System.out.println("切换到防御姿态");}
}
//武器战
public class WeaponWarrior extends Warrior {@Overridepublic void changeStance() {System.out.println("切换至战斗姿态");}
}
//测试类
public class WarriorTest {@Testpublic void testWarrior(){String type = "战场";Warrior warrior;switch (type) {case "MT":warrior = new TankWarrior();warrior.changeStance();break;case "战场":warrior = new WeaponWarrior();warrior.changeStance();break;case "输出":warrior = new FuryWarrior();warrior.changeStance();break;default:break;}}
}

通过上面这种硬编码的方式,在客户端进行逻辑判断(使用switch或者if-else)可以实现战士在不同场景下多的姿态切换,但是假设现在暴雪给战士又添加了一个新的姿态或者新的场景需要判断,那么就必须要在客户端代码中修改源码,非常不便于扩展,而且复杂的switch或者if-else语句都是非常不便于维护的,这时候策略模式就闪亮登场了!

策略模式:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化不会影响到使用算法的客户端。

那么现在我们使用策略模式再把上面的场景实现一次:

//战士类(环境角色)
public class Warrior {private Stance stance;public Warrior(Stance stance) {this.stance = stance;}public void changeStance(){stance.getStance();}
}
//姿态接口(抽象策略角色)
public interface Stance {void getStance();
}
//防御姿态
public class TankStance implements Stance {@Overridepublic void getStance() {System.out.println("切换到防御状态");}
}
//狂暴姿态
public class FuryStance implements Stance {@Overridepublic void getStance() {System.out.println("切换至狂暴状态");}
}
//武器姿态
public class WeaponStance implements Stance {@Overridepublic void getStance() {System.out.println("切换至战斗状态");}
}
//测试类
public class WarriorTest {@Testpublic void testWarrior(){Warrior w1 = new Warrior(new TankStance());w1.changeStance();Warrior w2 = new Warrior(new FuryStance());w2.changeStance();Warrior w3 = new Warrior(new WeaponStance());w3.changeStance();}
}

通过使用策略模式实现战士切换姿态的场景需求时,如果需要添加新的姿态或者场景,那么只需要添加一个算法就行了,相比硬编码的方式更容易维护和扩展。策略模式的重心不是在算法,而是封装算法,通过组织和调用算法让程序结构更加灵活。

  策略模式的优点:

(1) 策略模式定义了一系列的算法,所有这些算法都是完成相同的工作,只是实现不同,可以互相替换,减少了客户端和算法类之间的耦合

(2) 策略模式中的算法都可以进行单独的单元测试

(3) 策略模式避免了复杂的逻辑判断语句(switch或if-else)

策略模式的缺点:

       (1) 通过上面的示例返现,客户端必须知道所有的策略类,并且知道应该使用哪一个策略类。

(2) 如果算法种类过多,那么策略类的数量就会过于庞大。

扩展:

       使用简单工厂模式配合策略模式,可以让客户端不用自己来决定该使用哪一个策略,代码如下:

//生产状态对象的工厂类
public class StanceFactory {public static Stance getStance(String type){switch (type) {case "MT":return new TankStance();case "输出":return new FuryStance();case "战场":return new WeaponStance();default:return null;}}
}
//测试类
public class WarriorTest {@Testpublic void testWarrior(){String type = "战场";Stance stance = StanceFactory.getStance(type);if (stance!=null){Warrior warrior = new Warrior(stance);warrior.changeStance();}}
}

通过配合使用简单工厂模式,我们可以让客户端只需传入场景就可以由工厂来选择对应的策略,虽然解决了客户端判断策略的压力,但是工厂类的switch语句又导致程序的维护性和扩展行较差。我们可以使用反射和配置文件来对工厂类进行改进从而解决这个问题。代码如下:

//生产状态对象的工厂类
public class StanceFactory {private static Map<String, String> data;static{//这里使用Map模拟配置文件data = new HashMap<>();data.put("战场", "cn.eragon.domain.WeaponStance");data.put("MT", "cn.eragon.domain.TankStance");data.put("输出", "cn.eragon.domain.FuryStance");}public static Stance getStance(String type){String className = data.get(type);if (className!=null){try {return (Stance) Class.forName(className).newInstance();} catch (Exception e) {throw new RuntimeException(e);} }return null;}
}

《Java设计模式之策略模式》相关推荐

  1. ComeFuture英伽学院——2020年 全国大学生英语竞赛【C类初赛真题解析】(持续更新)

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  2. ComeFuture英伽学院——2019年 全国大学生英语竞赛【C类初赛真题解析】大小作文——详细解析

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  3. 信息学奥赛真题解析(玩具谜题)

    玩具谜题(2016年信息学奥赛提高组真题) 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业.有一天, 这些玩具小人把小南的眼镜藏了起来.小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的 ...

  4. 信息学奥赛之初赛 第1轮 讲解(01-08课)

    信息学奥赛之初赛讲解 01 计算机概述 系统基本结构 信息学奥赛之初赛讲解 01 计算机概述 系统基本结构_哔哩哔哩_bilibili 信息学奥赛之初赛讲解 02 软件系统 计算机语言 进制转换 信息 ...

  5. 信息学奥赛一本通习题答案(五)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  6. 信息学奥赛一本通习题答案(三)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  7. 信息学奥赛一本通 提高篇 第六部分 数学基础 相关的真题

    第1章   快速幂 1875:[13NOIP提高组]转圈游戏 信息学奥赛一本通(C++版)在线评测系统 第2 章  素数 第 3 章  约数 第 4 章  同余问题 第 5 章  矩阵乘法 第 6 章 ...

  8. 信息学奥赛一本通题目代码(非题库)

    为了完善自己学c++,很多人都去读相关文献,就比如<信息学奥赛一本通>,可又对题目无从下手,从今天开始,我将把书上的题目一 一的解析下来,可以做参考,如果有错,可以告诉我,将在下次解析里重 ...

  9. 信息学奥赛一本通(C++版) 刷题 记录

    总目录详见:https://blog.csdn.net/mrcrack/article/details/86501716 信息学奥赛一本通(C++版) 刷题 记录 http://ybt.ssoier. ...

  10. 最近公共祖先三种算法详解 + 模板题 建议新手收藏 例题: 信息学奥赛一本通 祖孙询问 距离

    首先什么是最近公共祖先?? 如图:红色节点的祖先为红色的1, 2, 3. 绿色节点的祖先为绿色的1, 2, 3, 4. 他们的最近公共祖先即他们最先相交的地方,如在上图中黄色的点就是他们的最近公共祖先 ...

最新文章

  1. ajax无刷新方式对form表单进行赋值!
  2. Bzoj4568: [Scoi2016]幸运数字
  3. RestTemplate技术预研-认识RestTemplate
  4. 测试:将手机摄像头用作网络摄像头的拍摄效果
  5. vue中安装sass
  6. Programming Computer Vision with Python【学习笔记】【第一章】
  7. 内网服务器时间修改,内网(无网络)搭建ntp时间同步服务
  8. mybatis 打印sql_不敢相信,相同SQL下Mybatis查询结果和数据库竟然不一样!
  9. Linux文件查看与查找命令
  10. java 素数 五行_(1)转载:八卦数论(二)
  11. scratch-www 在Win10下的环境配置
  12. 【操作系统】进程间通信 — 消息队列
  13. 华硕主板VMware中安装Ubuntu16.04中的BIOS设置问题
  14. 必备外文文献网站,有外文文献翻译功能
  15. IDC数据中心机房如何选择虚拟机和物理机?
  16. [生存志] 第87节 张仪犀首纵横大战
  17. 数据结构 - 逻辑结构和存储结构
  18. java基础巩固-宇宙第一AiYWM:为了维持生计,Spring全家桶_Part1-1(Spring左膀右臂中的左膀IOC第一篇~全是概念,Spring为啥辣么6)~整起
  19. mysql_row是什么类型的_【原创】8. MYSQL++中的Row类型
  20. 我不明白我,也不明白你

热门文章

  1. 武警中队智慧磐石,科技强勤,三维电子沙盘开发教程第十三课
  2. 浙政钉埋点 -- 稳定性监控代码(Emas)和流量分析代码(A+)
  3. 如何打开Mac电脑的静音模式?如何开启 Apple Watch 静音模式?
  4. multism中ui和uo应该怎么表示_南昌大学仿真实验(multism) -
  5. 启航:与冬日诀别,吻旷野苏醒
  6. 利用C#语言实现跨平台小闹钟
  7. 宏碁TravelMate tx50g2配置tensorflow-gpu
  8. 一键查找,批量修改CAD图纸的标注文字
  9. javascript 原型属性(prototype 属性)与 实例属性(自身属性)
  10. 行业分析-全球与中国阻燃过滤棉市场现状及未来发展趋势