继承很不错

小帅刚毕业就进了一家游戏公司工作,公司正在开发一款新的即时战略游戏,领导让他设计游戏里的兵种及行为。

在第一个版本里,只有步兵,骑士和弓箭手三个兵种,每个兵种都有移动,停止,攻击和自愈四种行为。

小帅马上做了个简单的设计,每个兵种都能移动和停止,不同的兵种有不同的战斗方式和回血速度。

于是设计了Unit(兵种)抽象类,实现了move()和stop()方法,各个兵种继承该超类,然后根据自己的战斗特点实现超类的中的fight()和selfHealing()抽象方法。

子类重用的了父类的代码,又根据自己的特点实现了抽象方法,嗯,小帅觉得很满意,就在小组中做了分享。

“我觉得还应该加个投石车兵种,攻城利器”,小组成员提议。

“没问题,加个投石车的子类就行了”,小帅自信地说。


”可是投石车明明不能自愈,却还要实现父类的selfHealing()方法,不觉得很奇怪吗?”项目组的老王立马指出了问题。

接口怎么样?

小帅立马想到了接口,把自愈方法单独抽离出来,放到一个自愈接口里,有自愈能力的兵种都继承该接口。没自愈能力的投石车,就不用继承了。

”这样看上去好多了,但是代码不能复用,每个子类都要重新实现fight()和selfHealing()方法,以后我们要设计几十个兵种,每个兵种都得重新实现一遍,这样太麻烦了。”老王犀利得指出了问题所在。

小帅一时语塞。

针对接口编程,而不是针对实现编程

老王看了看小帅一脸迷茫的样子,托了托眼镜,继续说道:“我们要找出应用中经常变化的部分,把它们独立出来,和那些不需要变动的代码区分开来,这是个重要的设计原则。”

“在这个例子中,fight()和selfHealing()方法每个子类的实现都不一样,属于经常变化的部分,我们可以设计SelfHealingBeHavior和FightBeHavior接口,把战斗行为和自愈行为提取出来,这样就应用了一个设计原则:针对接口编程,而不是针对实现编程。

“这里我们可以使用策略(Strategy)模式进行设计”,老王已经停不下来了,继续说道:
策略(Strategy)模式的定义如下:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

这里的战斗行为和自愈行为就是“算法”,我们把算法封装起来,各种战斗和自愈的实现方式都在子类中实现,客户端只要调用接口就行了,不用管具体是怎么实现的。

应用了策略模式后的类图:

说了这么多,也该上代码了。

FightBeHavior接口以及实现类

/*** 战斗接口* @author zhanyd*/
public interface FightBeHavior {/*** 战斗*/void fight();
}
/*** 剑战斗子类* @author zhanyd*/
public class FightWithSword implements FightBeHavior{public void fight() {System.out.println("攻击:看我的剑法");}
}
/*** 弓箭战斗子类* @author zhanyd*/
public class FightWithArrow implements FightBeHavior{public void fight() {System.out.println("攻击:我射箭-->");}
}
/*** 长枪战斗子类* @author zhanyd*/
public class FightWithSpear implements FightBeHavior{public void fight() {System.out.println("攻击:看我的长枪");}
}
/*** 石头战斗子类* @author zhanyd*/
public class FightWithStone implements FightBeHavior{public void fight() {System.out.println("攻击:我扔石头");}
}

SelfHealingBeHavior接口以及实现类

/*** 自愈接口* @author zhanyd*/
public interface SelfHealingBeHavior {/*** 自愈*/void selfHealing();
}
/*** 快速回血子类* @author zhanyd*/
public class SelfHealingFast implements SelfHealingBeHavior{public void selfHealing() {System.out.println("我每秒回血3%\n");}
}
/*** 中速回血子类* @author zhanyd*/
public class SelfHealingNormal implements SelfHealingBeHavior{public void selfHealing() {System.out.println("我每秒回血2%\n");}
}
/*** 慢速回血子类* @author zhanyd*/
public class SelfHealingSlow implements SelfHealingBeHavior{public void selfHealing() {System.out.println("我每秒回血1%\n");}
}

兵种类

/*** 兵种父类* @author zhanyd*/
public class Unit {protected String name;protected FightBeHavior fightBeHavior;protected SelfHealingBeHavior selfHealingBeHavior;public void move() {System.out.println("我是:" + name);System.out.println("向前挺进...");}public void stop() {System.out.println("原地待命...");}/*** 动态设置战斗方式* @param fi*/public void setFightBeHavior(FightBeHavior fi) {fightBeHavior = fi;}/*** 动态设置自愈速度* @param se*/public void setSelfHealingBeHavior(SelfHealingBeHavior se) {selfHealingBeHavior = se;}/*** 战斗*/public void fight() {fightBeHavior.fight();}/*** 自愈*/public void selfHealing() {selfHealingBeHavior.selfHealing();}
}
/*** 步兵* @author Administrator*/
public class Infantry extends Unit{public Infantry() {name = "步兵";// 用剑攻击fightBeHavior = new FightWithSword();// 回血速度慢selfHealingBeHavior = new SelfHealingSlow();}
}
/*** 弓箭手* @author zhanyd*/
public class Archer extends Unit{public Archer() {name = "弓箭手";// 用弓箭攻击fightBeHavior = new FightWithArrow();// 回血速度一般selfHealingBeHavior = new SelfHealingNormal();}
}
/*** 骑士* @author zhanyd*/
public class Knight extends Unit{public Knight() {name = "骑士";// 用长枪攻击fightBeHavior = new FightWithSpear();// 回血速度快selfHealingBeHavior = new SelfHealingFast();}
}
/*** 投石车* @author zhanyd*/
public class Catapult extends Unit{public Catapult() {name = "投石车";// 用石头攻击fightBeHavior = new FightWithStone();// 不能回血,不用设置回血功能}
}

测试类

public class TestUnit {public static void main(String[] args) {// 步兵出击Unit unit = new Infantry();unit.move();unit.fight();unit.stop();unit.selfHealing();// 弓箭手出击unit = new Archer();unit.move();unit.fight();unit.stop();unit.selfHealing();// 骑士出击unit = new Knight();unit.move();unit.fight();// 骑士扔掉了长枪,拔出了宝剑System.out.println("动态设置:骑士扔掉了长枪,拔出了宝剑!");unit.setFightBeHavior(new FightWithSword());unit.fight();unit.stop();unit.selfHealing();// 投石车出击unit = new Catapult();unit.move();unit.fight();unit.stop();// 修理工给投石车做了保养,投石车也能回血了System.out.println("动态设置:修理工给投石车做了保养,投石车也能回血了");unit.setSelfHealingBeHavior(new SelfHealingSlow());unit.selfHealing();}
}

测试结果

我是:步兵
向前挺进...
攻击:看我的剑法
原地待命...
我每秒回血1%我是:弓箭手
向前挺进...
攻击:我射箭-->
原地待命...
我每秒回血2%我是:骑士
向前挺进...
攻击:看我的长枪
动态设置:骑士扔掉了长枪,拔出了宝剑!
攻击:看我的剑法
原地待命...
我每秒回血3%我是:投石车
向前挺进...
攻击:我扔石头
原地待命...
动态设置:修理工给投石车做了保养,投石车也能回血了
我每秒回血1%

“setFightBeHavior(FightBeHavior fi)方法和setSelfHealingBeHavior(SelfHealingBeHavior se)方法,能在程序运行中动态的切换实现的算法,这是策略模式的一大优点。“,老王补充道。

小帅看着代码,陷入了沉思,真是越看越有味道。

“原来FightBeHavior接口就是兵器库(算法库),以后不管用到什么其他的战斗方式,只要在实现类里增加就行了,就像在兵器库(算法库)里增加兵器(算法),比如:双节棍,大刀,流星锤等等,如果有新的兵种直接拿来用就行了,实现了类的复用。

战斗方式可以随时替换,并且不会影响到具体兵种的使用。“小帅貌似明白了策略模式的精髓所在,显得有点兴奋。

老王点点头,开心的笑了,“就是这样啊,你已经学会策略模式了”。

代码链接

策略模式玩转步兵,骑士和弓箭手相关推荐

  1. 从真实项目中抠出来的设计模式——第一篇:策略模式

    有时候因为种种原因导致我们会写出很多丑陋的代码,比如赶工时,短暂性的偷懒,不会设计模式等等导致代码沉积,一个cs上万行代码这样场景是有发生, 当然这里也包括我...所以时间充裕一点之后就想重构一下,毕 ...

  2. java策略案例国王,骑士_实例说明策略模式

    最近工作不是很多,正好抽出时间学习一下期待已经的设计模式,作为一名刚毕业一年的开发人员更应该多抽出些时间了解一下设计模式. 此片文章对策略模式做一个总结,希望对大家有帮助. (题外话:策略模式之前只是 ...

  3. [设计模式学习笔记] -- 策略模式

    策略模式 定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 举一个简单的例子来描述策略模式. 设计一款冷兵器时代士兵打仗的游戏,游戏内部设计要使用OO技术. ...

  4. 设计模式之一——从魔兽争霸的兵种和技能看策略模式

    很多人都喜欢玩魔兽争霸,里面的兵种很多,比如有Footman步兵.Knight骑士.Grunt兽人步兵,他们使用不同的武器,Footman步兵使用宝剑攻击.knight也使用sword宝剑攻击,gru ...

  5. 趣谈设计模式 | 策略模式(Strategy):你还在使用冗长的if-else吗?

    文章目录 案例:指挥官AI 策略模式 配合工厂模式 总结 完整代码与文档 案例:指挥官AI 案例可能不符合实际逻辑,仅用于表述设计模式的思想,勿介意 假设我们开发了一款类似全面战争的即时战略游戏,为了 ...

  6. 【设计模式第一弹】策略模式

    目录 前言 啥是策略模式 三个角色 开波 定义及实现武器使用行为策略 定义及实现角色策略 定义上下文 最后一步,设置上下文背景 结果如何 结语 前言 以前一直就想整理一下以前使用过的设计模式,趁着现在 ...

  7. Java设计模式之十一 ---- 策略模式和模板方法模式

    前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...

  8. 从零开始单排学设计模式「策略模式」黑铁 II

    阅读本文大概需要 1.7 分钟. 本篇是设计模式系列的第三篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统.所以现在打算重写,加上距离现在也有一段时间了, ...

  9. python策略模式_设计模式(python实现):策略模式

    策略模式简单说和小时候我们玩的玩具差不多,一堆零部件通过不同的拼凑构成几个不同的机器人. 1.举个栗子 我们买了一个机器人,同时这个机器人配了三把武器,三把武器可以替换使用 2.Show in Cod ...

最新文章

  1. linux 获取cpu id,linux获取cpu id和disk id
  2. 57张图,13个实验,干死 MySQL 锁!
  3. DNS主从服务器不同步的解决方法
  4. Boost:std ::bind与Boost的_1绑定的测试程序
  5. 全栈Python 必备库
  6. python与正则表达式(part1)--元字符
  7. 一步步编写操作系统 33 利用bios中断0x15子功能0xe820获取内存
  8. leetcode - 543. 二叉树的直径
  9. pycharm 激活方法分享(有效期至2099)
  10. Linux DNS 服务配置 (非常详细)
  11. mybatis逆向工程用idea通过pom插件generator生成代码指令(mysql,oracle,sqlserver)
  12. FPGA学习——Vivado2017.4安装教程
  13. python3.9.5安装教程加汉化
  14. 顺序表练习(三):对称矩阵的压缩储存
  15. 数据仓库建模方法/范式建模法/维度建模法/事实表/维度表/优缺点/建模流程/概念建模/逻辑建模/物理建模
  16. TestProject 自动化
  17. 中学计算机竞赛教程,全国中小学信息技术课程教学大赛获奖案例初中信息技术八年级-设置自定义动画动作路径...
  18. Linux C 以read()读取文件并提取字符串
  19. centos 7系统Give root password for maintenance解决办法
  20. Android3d结构光,安卓阵营独一份!OPPO完成3D结构光技术研发,某果开始慌了

热门文章

  1. Matlab plot()自定义线宽及保存高清大图
  2. 教你用C计算2的n次方
  3. GitHub获百万下载的阿里P5-P9必刷知识体系图核心手册
  4. 如何向MongoDB数据库导入数据
  5. 计算机管理看板方式,Kanban|看板-现场管理-太友科技专业提供现场可视化整体解决方案...
  6. 解决在H170/B150主板不接显示器无法正常开机的问题
  7. js form 上传文件
  8. 软件开发团队如何有效地沟通与协作?
  9. oracle数据库不交费能用吗,如何减少Oracle数据库的License和支持费用
  10. 汇编–从数据类型看WORD与DWORD