转载注明出处:https://blog.csdn.net/qq_39071530/article/details/84172844
github地址 https://github.com/esmusssein777/designpatterns
所有设计模式目录 https://blog.csdn.net/qq_39071530/article/details/84849070
首先关心的是什么时候要用到策略模式!
我们来关心下面的例子。
英雄联盟的英雄有四个基础技能和两个召唤师技能。
每个英雄的基础技能都不相同(对应的是Q、W、E、R),
但是召唤师技能却是在多个里面选择的,可以相同(对应D、F)。
我们先来考虑一种情况。
我们将超类设计成
我们会发现有以下的缺点:
1、代码在多个子类中重复(实现召唤师技能的D和F的代码重复)
2、运行时行为不容易改变(我们在选择召唤师技能DF时需要重新的覆盖D、F)
3、很难知道召唤师技能的全部行为(假如版本改变,召唤师技能DF也改变)
4、改变会牵一发动全身,如果某个召唤师技能覆盖错误会导致bug。
于是我们定义一个接口,至于有什么好处可以看我的EffectiveJava学习笔记系列。
以下的就是定义了行为类。
定义一个召唤师技能的行为。里面有传送、闪现、治疗等等。
我们来看一下完整的类uml图
我们创建了EZ和VN两个英雄来继承超类。
在里面分别的实现自己的qwer技能。
并选择召唤师技能的行为作为自己的 d、f 技能。
下面是代码
Hero.java
package org.ligz.DesignPatterns.Strategy.hero;
public abstract class Hero {
DFBehavior dBehavior;//使用D技能
DFBehavior fBehavior;//使用F技能
public Hero() {
System.out.println("创建英雄");
}
public void DSkill() {
dBehavior.skill();
}
public void FSkill() {
fBehavior.skill();
}
public void fight() {
System.out.println("打架");
}
/**
* 基础技能
*/
public abstract void Q();
public abstract void W();
public abstract void E();
public abstract void R();
}
DFBehavior.java
package org.ligz.DesignPatterns.Strategy.hero;
public interface DFBehavior {
public void skill();
}
Falsh.java
package org.ligz.DesignPatterns.Strategy.hero;
public class Falsh implements DFBehavior{
public void skill() {
System.out.println("使用闪现");
}
}
Cure.java
package org.ligz.DesignPatterns.Strategy.hero;
public class Cure implements DFBehavior{
public void skill() {
System.out.println("使用治疗");
}
}
TP.java
package org.ligz.DesignPatterns.Strategy.hero;
public class TP implements DFBehavior{
public void skill() {
System.out.println("使用传送");
}
}
EZ.java
package org.ligz.DesignPatterns.Strategy.hero;
public class EZ extends Hero{
public EZ() {
super();
System.out.println("是时候展示真正的技术了");
dBehavior = new Falsh();
fBehavior = new TP();
}
@Override
public void Q() {
System.out.println("EZ的q技能");
}
@Override
public void W() {
System.out.println("EZ的w技能");
}
@Override
public void E() {
System.out.println("EZ的e技能");
}
@Override
public void R() {
System.out.println("EZ的r技能");
}
}
VN.java
package org.ligz.DesignPatterns.Strategy.hero;
public class VN extends Hero{
public VN() {
super();
System.out.println("让我们来猎杀那些陷入黑暗中的敌人");
dBehavior = new Falsh();
fBehavior = new Cure();
}
@Override
public void Q() {
System.out.println("VN的q技能");
}
@Override
public void W() {
System.out.println("VN的w技能");
}
@Override
public void E() {
System.out.println("VN的e技能");
}
@Override
public void R() {
System.out.println("VN的r技能");
}
}
下面是测试的代码
package org.ligz.DesignPatterns.Strategy.hero;
public class Test {
public static void main(String[] args) {
Hero ez = new EZ();
ez.fight();
ez.DSkill();
ez.FSkill();
System.out.println("+++++++++++++++");
Hero vn = new VN();
vn.fight();
vn.DSkill();
vn.FSkill();
}
}
创建英雄
是时候展示真正的技术了
打架
使用闪现
使用传送
+++++++++++++++
创建英雄
让我们来猎杀那些陷入黑暗中的敌人
打架
使用闪现
使用治疗
我们脱离例子来分析代码,会发现 “有一个” 可能比 ”是一个” 更好。
英雄Hero类有一个行为是DF召唤师技能。
每一个英雄都有一个DFBehavior行为,好处是将召唤师技能委托给他代为处理,这里可能是有多个行为。比如说符文也可以是一个Behavior行为。我们同样用这种方式扩展。
这种做法和继承不同的地方在于,英雄的行为不是继承来的,而是适当的行为对象组合来的。
这样做有很大的弹性。
回到定义:
策略模式定义了算法族(召唤师技能,或者说是符文),分别封装起来,让他们之间可以相互替换,此模式可以让算法的变化独立于使用算法的客户(英雄)。