前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式-策略模式

设计模式-策略模式

作者头像
子乾建建-Jeff
发布2020-06-29 15:16:51
5690
发布2020-06-29 15:16:51
举报
文章被收录于专栏:iBroProiBroPro

策略模式

Strategy Pattern: Define a family of algorithms, encapsulateeach one, and make them interchangeable. Strategy lets thealgorithm vary independently from clients that use it.

定义一系列算法,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

把类(A)中的某一些方法,单独抽取为接口(B),变成 has-a 的关系,接口(B)的实现类具体完成某种算法/操作。B 接口的实现类称为策略类。

在A类中通过一个方法调用接口B中的方法,而具体的调用:由A的子类和接口B的实现类进行关联。

后续的更改接口B的实现类和A类的子类即可。便于动态改变、新增一些实现方法。

不明觉厉

看个实例:

某款游戏有一个角色(Character)类,具体角色包括国王(King)、皇后(Queen)、骑士(Knight)、妖怪(Troll),他们有赤手空打方法 fight(),使用武器攻打方法 useWeapon()。

做出类图 图1:

图1: 角色及其子类

现在完美的使用了类的继承机制,但仍然存在以下问题:

1 Queen 和 Troll 的代码存在重复,后面如果再有新角色,仍然使用匕首,同样需要重复书写。

2 如果再新增角色,一个小兵使用武器小刀,一个领帅使用长矛和匕首,新增两个类同时还有代码重复。如果新增 5 个,10 个角色,修改难度则变大。

代码如下:

代码语言:javascript
复制
// Character角色类
public class Character {
  public void fight() {
    System.out.println("赤手空拳就是干");
  }
  public void useWeapon() {}
}
//国王类
public class King extends Character {
  public void useWeapon() {
    System.out.println("国王还会使用宝剑");
  }
}
//皇后类
public class Queen extends Character {
  public void useWeapon() {
    System.out.println("皇后还会使用匕首");
  }
}
//骑士类
public class Knight extends Character {
  public void useWeapon() {
    System.out.println("骑士还会使用斧头");
  }
}
//怪兽类
public class Troll extends Character {
  public void useWeapon() {
    System.out.println("妖怪还会使用匕首");
  }
}
//主方法
public class Start {

  public static void main(String[] args) {
    Character king = new King();
    king.fight();
    king.useWeapon();

    Character queen = new Queen();
    queen.fight();
    queen.useWeapon();

    Character knight = new Knight();
    knight.fight();
    knight.useWeapon();

    Character troll = new Troll();
    troll.fight();
    troll.useWeapon();

  }

}

执行结果:

策略模式登场

既然这个行为(方法)具有如此多的变化性,不妨把它抽取出来。在角色类中我们只说执行使用武器的方法,具体的武器另实现。让具体的角色调用具体的武器。

类图变为图2:

图2:角色类/武器行为接口图

现在,新增角色,让其继承 Character 类即可;

新增武器,让武器实现WeaponBehavior接口即可。

至于使用的武器,在新增的角色类中来进行调用。

代码:

代码语言:javascript
复制
//Character角色类
import cn.headFirst.strategyMode.weapon.WeaponBehavior;
public class Character {

  public WeaponBehavior weaponBehavior;

  public void fight() {
    System.out.println("赤手空拳就是干");
  }
  public void performUseWeapon() {
    weaponBehavior.useWeapon();
  }
}
//国王类
import cn.headFirst.strategyMode.weapon.SwordBehavior;

public class King extends Character {
  public King() {
    weaponBehavior = new SwordBehavior();
  }
}
//皇后类
import cn.headFirst.strategyMode.weapon.KnifeBehavior;

public class Queen extends Character {
  public Queen() {
    weaponBehavior = new KnifeBehavior();
  }
}
//骑士类
import cn.headFirst.strategyMode.weapon.AxeBehavior;

public class Knight extends Character {

  public Knight() {
    weaponBehavior = new AxeBehavior();
  }
}
//怪兽类
import cn.headFirst.strategyMode.weapon.KnifeBehavior;

public class Troll extends Character {
  public Troll() {
    weaponBehavior = new KnifeBehavior();
  }
}
代码语言:javascript
复制
//武器接口
package cn.headFirst.strategyMode.weapon;
public interface WeaponBehavior {
  public void useWeapon();
}
//使用宝剑
package cn.headFirst.strategyMode.weapon;
public class SwordBehavior implements WeaponBehavior {

  @Override
  public void useWeapon() {
    System.out.println("使用宝剑攻打");
  }
}
//使用弓箭
package cn.headFirst.strategyMode.weapon;
public class BowAndArrowBehavior implements WeaponBehavior {

  @Override
  public void useWeapon() {
    System.out.println("使用弓箭攻打");
  }
}
//使用斧头
package cn.headFirst.strategyMode.weapon;
public class AxeBehavior implements WeaponBehavior {
  @Override
  public void useWeapon() {
    System.out.println("使用斧头攻打");
  }
}
//使用匕首
package cn.headFirst.strategyMode.weapon;
public class KnifeBehavior implements WeaponBehavior {
  @Override
  public void useWeapon() {
    System.out.println("使用匕首攻打");
  }
}
代码语言:javascript
复制
package cn.headFirst.strategyMode.character;
public class Start {
  public static void main(String[] args) {
    Character king = new King();
    king.fight();
    king.performUseWeapon();

    Character queen = new Queen();
    queen.fight();
    queen.performUseWeapon();

    Character knight = new Knight();
    knight.fight();
    knight.performUseWeapon();

    Character troll = new Troll();
    troll.fight();
    troll.performUseWeapon();
  }
}

执行结果:

问题星球再次抛出问题:

这样,我可以动态设置武器吗?

动态设置武器,就是执行过程中是可以让他切换武器,升级装备。

答案是肯定的,简单修改一下,在Character类中,给weaponBehavior加一个set方法,其余的保持不变,如图3。

图3:增加set方法后的Character类

代码如下:

代码语言:javascript
复制
//Character类中新增
public void setWeaponBehavior(WeaponBehavior weaponBehavior) {
    this.weaponBehavior = weaponBehavior;
  }
//主方法 执行中给国王新增一个武器 弓箭
    king.fight();
    king.performUseWeapon();
    king.setWeaponBehavior(new BowAndArrowBehavior());
    king.performUseWeapon();

结果:

在执行过程中,我们通过 setWeaponBehavior 方法就动态的为某一个对象新增武器。

由客户端决定在什么情况下使用哪种方法,客户端的压力比较大。

客户端:我是谁?我在哪?我要调用谁?

你要调用的就是策略,策略,策略。

原来策略模式用起来就是这样的啊,我的天,建了这么多类。

在上下文中找出行为策略,新建各种策略类,客户端去调用吧。

策略模式优点:

  • 对“开闭原则”完美支持;
  • 提供了管理相关的算法族的办法
  • 提供了可以替换继承关系的办法
  • 避免使用多重条件转移语句
  • 提供了一种算法的复用机制

策略模式缺点:

  • 客户端必须知道所有的具体实现的策略类,并决定调用哪一个。
  • 策略类个数过多,造成项目代码中类个数过多。

感谢阅读,感谢陪伴!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iBroPro 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档