博主声明:
转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。
晚上的时候,抽了点时间看了一下设计模式相关书籍,毕竟有些东西还是得重温一下的,脑子不灵光,记住不啊。看着看着就看到了策略设计模式,关于这个策略模式,它书本上是这样定义的:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
关于策略模式,这本书上是用了一个理财利率计算的例子,那么理财的软件有非常多,像余额宝这样的,把钱存进去就可以得到一点收入,也是非常不错的。而理财软件并非只有这个,不同的人可能用的软件都不一样,所有这里肯定就有利率计算的区别了。我可能把钱分别投入到不同的理财软件,那么每日收入当然就是不同的了,所有这里就用了不同的收益算法。
那么这里的收益算法必定和软件息息相关,不同的软件收益不同,那我们向不同软件投资就是不同的策略,可能看哪个比较高,就往那个软件里面存一点钱,就用到了策略设计模式。
不过呢,我在看策略设计模式时,忽然想到了三国中的诸葛亮,说到策略,我印象里记忆最深刻的还是诸葛亮了,在三国时期,那策略可真是无以匹敌啊。这样一关联起来,我就马上想写一个诸葛亮排兵布阵的策略模式。
接下来,我要介绍一下代码的意思,故事发生在三国时期,忽然刘备的驻军遭到了敌人的袭击,而五虎上将分别从其他不同的地方赶过来支援,由于派兵需要比对两军之间的战斗力及战耗情况,所以诸葛亮要用最大的利益来换取胜利与战绩。
诸葛亮手下有五虎上将:张飞,关羽,赵云,马超,黄忠。但只能派出一位作战,而且五虎上将的实力各不相同,且拥有的战力和士兵人数也不同。我们来看一下具体情况:
我军大将:
- 张飞:拥兵 9500 人,战斗力 2.35
- 关羽:拥兵 9000 人,战斗力 2.45
- 赵云:拥兵 8500 人,战斗力 2.55
- 马超:拥兵 10000 人,战斗力 2.30
- 黄忠:拥兵 11000 人,战斗力 2.20
敌军大将:
- 曹操:拥兵 18000 人,战斗力 1.20
好了,拟定的战力表已经确定,那么这场战争的胜利和战绩都掌握在诸葛亮手中,诸葛亮利用了一些简单的计算,根据双方的拥兵数量和战力进行了比较,最后得出应该派遣哪一位五虎上将去支援才能获得最好的战绩,还有要考虑战损情况。
接着直接上代码,一个是诸葛亮类:
package com.xww.dp.strategy;
/**
* 诸葛亮,军师策略,发兵操作。
*
* @author xww
*
* @博客 :https://blog.csdn.net/smile_running?t=1
*
*/
public class Zhugeliang {
private int enemy;// 敌军人数
private float enemyfighting;// 战斗力
// 五虎将
public enum Wuhu {
zhangfei, guanyu, zhaoyun, machao, huangzhong
}
public Zhugeliang(int enemy, float fighting) {
this.enemy = enemy;
this.enemyfighting = fighting;
}
// 派遣军队
public String dispatchTroops(Wuhu wuhu) {
switch (wuhu) {
case zhangfei:
return zhangfeiArmy();
case guanyu:
return guanyuArmy();
case zhaoyun:
return zhaoyunArmy();
case machao:
return machaoArmy();
case huangzhong:
return huangzhongArmy();
}
return "";
}
// 张飞的军队
private String zhangfeiArmy() {
int army = 9500;
float fighting = 2.35f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyfighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
// 关羽的军队
private String guanyuArmy() {
int army = 9000;
float fighting = 2.45f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyfighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
// 赵云的军队
private String zhaoyunArmy() {
int army = 8500;
float fighting = 2.55f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyfighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
// 马超的军队
private String machaoArmy() {
int army = 10000;
float fighting = 2.3f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyfighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
// 黄忠的军队
private String huangzhongArmy() {
int army = 11000;
float fighting = 2.2f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyfighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
}
这个类就是诸葛亮通过对比两军战力的相关算法,对比了五位将军的战力和兵力,通过简单的计算来模拟一下,然后另一个是主类:
package com.xww.dp.strategy;
import com.xww.dp.strategy.Zhugeliang.Wuhu;
public class StrategyPatternClient {
public static void main(String[] args) {
int enemy = getEnemy();
float fighting = getFighting();
Zhugeliang liang = new Zhugeliang(enemy, fighting);
String result = liang.dispatchTroops(Wuhu.zhangfei);
//张飞 725
//关羽 450
//赵云 75
//马超 1400
//黄忠 2600
System.out.println(result);
}
public static int getEnemy() {
int enemyCount = 18000;
System.out.println("获得敌情,敌人数量:" + enemyCount + "人");
return enemyCount;
}
public static float getFighting() {
float fighting = 1.2f;
System.out.println("敌人战力:" + fighting + "倍");
return fighting;
}
}
根据简单的模拟战斗,可以得出双方交战的战绩情况。我们把五位上将的战绩列出来:
上面运行结果是每一位的战绩情况,根据没一位将军的拥兵数量和战斗力计算出来的。它们的剩余士兵就是战绩,接下来我们来计算一下他们的战斗损失情况。
战斗损失:
- 张飞 :拥兵 9500,剩余 725,损失 8775 人
- 关羽 :拥兵 9000,剩余 450,损失 8550 人
- 赵云 :拥兵 8500,剩余 75,损失 8425 人
- 马超 :拥兵 10000,剩余 1400,损失 8600 人
- 黄忠:拥兵 11000,剩余 2600,损失 8400 人
计算一下战斗损失,还是诸葛亮老谋深算,乍一看关羽、赵云比较牛皮,这赵云差点就锤不过了,别看马超拥兵比较多,战斗损失却比赵云、关羽还多。综上情况,诸葛亮还是派遣老黄盖出马,所谓老将出马,一个顶俩。
好了,这个例子就是这样的,也是我自己瞎想着玩的,感觉非常有意思,就用代码实现了一下。至此,我们还没有用上策略模式,虽然诸葛亮料事如神, 但是我们把代码写出这样,他还不得气死,从未见过如此厚颜无耻之人。
策略模式的运用
接下来,才是我们的策略模式具体使用情况,关于策略模式的定义,它是说把这一系列算法一个一个的封装起来,并且使其能够相互替换。这样的话,我们上面代码中的算法部分,就只有五虎上将和敌军的战力比较情况了,比如这一部分:
// 赵云的军队
private String zhaoyunArmy() {
int army = 8500;
float fighting = 2.55f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyfighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
根据策略模式的使用规则,要把算法封装为一个类,也就是把上部分代码封装到类里面去。有了这样的思想,我们事情就好办了,为五虎上将建立五个类,把算法搬到里面去,这是第一步要做的。
策略模式还指出需要根据算法替换不同的类,也就是诸葛亮可以派遣五虎上将中的任何一位都可以,所以这里需要一个接口,根据多态性,我们可以传入它的不同实现类。下面开始着手改为策略模式吧!
首先,新建一个接口,传入敌军的人数和战力值,返回的是战斗结果,如下:
package com.xww.dp.strategy;
/**
* 诸葛亮策略接口
*
* @author xww
* @博客 https://blog.csdn.net/smile_running?t=1
*/
public interface ZhugeliangStrategy {
// 派遣五虎上将
String wuhu(int enemy, float enemyFlighting);
}
接下来是对每一个五虎上将的算法封装,代码如下:
package com.xww.dp.strategy;
/**
* 五虎上将 - 张飞
*
* @author xww
*
*/
public class ZhangFei implements ZhugeliangStrategy {
public ZhangFei() {
}
@Override
public String wuhu(int enemy, float enemyFlighting) {
int army = 9500;
float fighting = 2.35f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyFlighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
}
要实现刚刚创建的策略接口,把算法部分考过来就行了,剩余四个都是这样的操作,看看就懂了。关羽类的代码:
package com.xww.dp.strategy;
public class GuanYu implements ZhugeliangStrategy {
public GuanYu() {
}
@Override
public String wuhu(int enemy, float enemyFlighting) {
int army = 8500;
float fighting = 2.55f;
// 敌人实力
int enemyStrength = (int) (enemy * enemyFlighting);
// 我军实力
int zhangfeiStrength = (int) (army * fighting);
// 战斗结果
int soldier = zhangfeiStrength - enemyStrength;
return soldier > 0 ? "战胜!剩余士兵:" + soldier : "战败!";
}
}
剩下的赵云、马超、黄忠三个类就不贴代码了,几乎一摸一样。接着,诸葛亮类也需要做出相应的修改,我们之前的派遣军队是一个 enum 类型,这里就要改成接口类型了。
package com.xww.dp.strategy;
/**
* 诸葛亮,军师策略,发兵操作。
*
* @author xww
*
* @博客 :https://blog.csdn.net/smile_running?t=1
*
*/
public class Zhugeliang {
private int enemy;// 敌军人数
private float enemyfighting;// 战斗力
public Zhugeliang(int enemy, float fighting) {
this.enemy = enemy;
this.enemyfighting = fighting;
}
// 派遣军队
public String dispatchTroops(ZhugeliangStrategy strategy) {
return strategy.wuhu(enemy, enemyfighting);
}
}
对比一下,算法部分全部被移到了每一个类中,而且诸葛亮类也与几个五虎上将解耦了,他们通过一个接口联系。最后,我们的客户端就可以这样调用了:
package com.xww.dp.strategy;
public class StrategyPatternClient {
public static void main(String[] args) {
int enemy = getEnemy();
float fighting = getFighting();
Zhugeliang liang = new Zhugeliang(enemy, fighting);
// 这里直接 new 策略的实现类
String result = liang.dispatchTroops(new HuangZhong());
System.out.println(result);
}
public static int getEnemy() {
int enemyCount = 18000;
System.out.println("获得敌情,敌人数量:" + enemyCount + "人");
return enemyCount;
}
public static float getFighting() {
float fighting = 1.2f;
System.out.println("敌人战力:" + fighting + "倍");
return fighting;
}
}
好了,这就是策略模式的基本代码了,把每个算法封装为类,提供一个算法的接口,通过实现该接口实现不同的算法,然后调用时,只要有 new 算法实现了就是不同的策略了,而且都可以随便替换的,这就是策略模式。