一.什么是策略模式
(1)策略模式属于对象的行为模式。其用意是针对一组算法,将每一
个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替
换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
(2)策略模式是对算法的包装,是把使用算法的责任和算法本身分
割开来,委派给不同的对象管理。策略模式通常把一个系列的算法
包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句
话来说,就是:“准备一组算法,并将每一个算法封装起来,使得
它们可以互换”。
二.策略模式的结构
(1)这个模式涉及到三个角色:
环境(Context)角色:持有一个Strategy的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个
接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
(2)策略模式的重心
策略模式的重心不是如何实现算法,而是如何组织、调用这些算
法,从而让程序结构更灵活,具有更好的维护性和扩展性。
(3)算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一
系列具体的策略算法,大家的地位是完全一样的,正因为这个平等
性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
(4)运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现
对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
(5)公有的行为
经常见到的是,所有的具体策略类都有一些公有的行为。这时候
,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。
当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。
这其实也是典型的将代码向继承等级结构的上方集中的标准做法。
三.以王者荣耀为例说明
UML类图.JPG王者荣耀里面召唤师技能(Summoner Spells)有:
召唤师技能.png
惩戒:对身边的野怪和小兵造成真实伤害并眩晕1秒(30秒的CD,1级解锁)
斩杀:立即对身边敌军英雄造成其已损失生命值14%的真实伤害(90秒CD,3级解锁)
狂暴:增加攻击速度60%,并增加物理攻击力10%持续5秒(60秒CD,5级解锁)
疾跑:增加30%移动速度持续10秒(100秒CD,7级解锁)
治疗术:回复自己与附近队友15%生命值,提高附近友军移动速度15%持续2秒(120秒CD,9级解锁)
干扰:沉默机关持续5秒(60秒CD,11级解锁)
眩晕:晕眩身边所有敌人0.75秒,并附带持续1秒的减速效果(90秒CD,13级解锁)
净化:解除自身所有负面和控制效果并免疫控制持续1.5秒(120秒CD,15级解锁)
弱化:减少身边敌人伤害输出30%持续2.5秒(90秒CD,17级解锁)
闪现:向指定方向位移一段距离(120秒CD,19级解锁)
将里面的召唤师技能抽象出来有(攻击方式,效果持续时间,冷却
时间,解锁等级等规则),而这些规则算法封装起来使得它们可以
互换。
建立一个抽象策略(Strategy)角色类SummonerSpells:
public interface SummonerSpells{
public void use(Self self,Enermy enermy){
//do something
}
}
实体类:
package com.lrq.test;
public class Enermy {
private int cd;
private int level;
private boolean lock;
private double currentHp;
private double fullHp;
private double attack;
private String controlEffect;
private String shift;
private double moveSpeed;
public Enermy() {
super();
}
public int getCd() {
return cd;
}
public void setCd(int cd) {
this.cd = cd;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public boolean isLock() {
return lock;
}
public void setLock(boolean lock) {
this.lock = lock;
}
public double getCurrentHp() {
return currentHp;
}
public void setCurrentHp(double currentHp) {
this.currentHp = currentHp;
}
public double getFullHp() {
return fullHp;
}
public void setFullHp(double fullHp) {
this.fullHp = fullHp;
}
public double getAttack() {
return attack;
}
public void setAttack(double attack) {
this.attack = attack;
}
public String getControlEffect() {
return controlEffect;
}
public void setControlEffect(String controlEffect) {
this.controlEffect = controlEffect;
}
public String getShift() {
return shift;
}
public void setShift(String shift) {
this.shift = shift;
}
public double getMoveSpeed() {
return moveSpeed;
}
public void setMoveSpeed(double moveSpeed) {
this.moveSpeed = moveSpeed;
}
@Override
public String toString() {
return "Enermy [cd=" + cd + ", level=" + level + ", lock=" + lock
+ ", currentHp=" + currentHp + ", fullHp=" + fullHp
+ ", attack=" + attack + ", controlEffect=" + controlEffect
+ ", shift=" + shift + ", moveSpeed=" + moveSpeed + "]";
}
}
--------------------------------------------------------------------------
package com.lrq.test;
public class Self {
private int cd;
private int level;
private boolean lock;
private double currentHp;
private double fullHp;
private double attack;
private String controlEffect;
private String shift;
private double moveSpeed;
public Self() {
super();
}
public int getCd() {
return cd;
}
public void setCd(int cd) {
this.cd = cd;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public boolean isLock() {
return lock;
}
public void setLock(boolean lock) {
this.lock = lock;
}
public double getCurrentHp() {
return currentHp;
}
public void setCurrentHp(double currentHp) {
this.currentHp = currentHp;
}
public double getFullHp() {
return fullHp;
}
public void setFullHp(double fullHp) {
this.fullHp = fullHp;
}
public double getAttack() {
return attack;
}
public void setAttack(double attack) {
this.attack = attack;
}
public String getControlEffect() {
return controlEffect;
}
public void setControlEffect(String controlEffect) {
this.controlEffect = controlEffect;
}
public String getShift() {
return shift;
}
public void setShift(String shift) {
this.shift = shift;
}
public double getMoveSpeed() {
return moveSpeed;
}
public void setMoveSpeed(double moveSpeed) {
this.moveSpeed = moveSpeed;
}
@Override
public String toString() {
return "Self [cd=" + cd + ", level=" + level + ", lock=" + lock
+ ", currentHp=" + currentHp + ", fullHp=" + fullHp
+ ", attack=" + attack + ", controlEffect=" + controlEffect
+ ", shift=" + shift + ", moveSpeed=" + moveSpeed + "]";
}
}
---------------------------------------------------------------------------------
然后建立几个具体策略(Strategy)角色类:
1.惩戒Discipline(打野专用)
public interface Discipline{
public void use(Self self,Enermy enermy){
enermy.currentHp - = 850;
enermy.controlEffect = "眩晕1秒";
}
}
2.斩杀(前排专用)
public interface Beheaded{
public void use(Self self,Enermy enermy){
enermy.currentHp-= (enermy.fullHp-enermy.currentHp)*14%;
}
}
3.闪现(adc)
public interface Flash{
public void use(Self self,Enermy enermy){
self.shif+=100;
self.controlEffect="向前闪现一小段";
}
}
4.治疗(adc或者辅助)
public interface Treatment{
public void use(Self self,Enermy enermy){
self.currentHp+=self.fullHp*15%;
self.moveSpeed+= self.moveSpeed*15%;
self.controlEffect="回复自己与附近队友15%生命值,提高附近友军移动速度15%持续2秒";
}
}
--------------------------------------------------------------------------------------------------------
然后环境(Context)角色:Summoner----召唤师
public class Summoner{
//持有一个具体的策略对象
private SummonerSpells summonerSpells;//召唤师技能
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Summoner(SummonerSpells summonerSpells){
this.summonerSpells= summonerSpells;
}
/**
* 计算生命值,控制效果,移速等
* @param Enermy,Self 敌人,自己
* @return
*/
public void quote(Self self,Enermy enermy){
return summonerSpells.use(Self self,Enermy enermy);
}
}
--------------------------------------------------------------------------------------------------------
最后客户端Client :
public class Client {
public static void main(String[] args) {
//选择并创建需要使用的策略对象
Flash flash= new flash(new Self(),new Enermy());
//创建环境
Summoner summoner= new Summoner(flash);
//计算属性
flash.use();
}
}
四.策略模式的优缺点
1. 策略模式的优点:
(1)策略模式提供了管理相关的算法族的办法。策略类的等级结构
定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里
面,从而避免代码重复。
(2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件
语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或
行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承
的办法还要原始和落后。
2.策略模式的缺点:
(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略
类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当
的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,
如果备选的策略很多的话,那么对象的数目就会很可观。
网友评论