设计模式-策略模式-以游戏BOSS设计为例

简介

策略模式定义

它定义了一系列算法,将每个算法都封装起来,并且使它们之间可以替换。策略模式让算法的变化独立于使用算法的客户端,即让算法变化不会影响到使用算法的客户端。

这个定义很难解释,我的理解是客户端可能会在多个不同的位置调用甚至组合调用算法,为了实现算法的复用与替换,算法独立出来,提供一个接口供客户端使用,客户端在接口中调用不同的算法,从而使算法与客户端隔离。

具体我们通过案例实现来了解

案例

假如我们现在正在设计一个BOSS,这个BOSS主要有三个动作普攻,技能,闪避。这三个动作可能不是一个BOSS专属的,可能其他BOSS也会复用,并且这个BOSS的技能后续可能也会调整。这个时候我们就需要采取策略模式来设计。

BOSS超类

Data
//BOSS超类
public abstract class Boss {
    protected String name;
    //动作组
    protected IAttack attack;
    protected IDodge dodge;
    protected ISkill skill;
    public Boss setAttack(IAttack iAttack)
    {
        this.attack=iAttack;
        return this;
    }
    public Boss setDodge(IDodge iDodge)
    {
        this.dodge=iDodge;
        return this;
    }
    public Boss setSkill(ISkill iSkill)
    {
        this.skill=iSkill;
        return this;
    }
    //需要注意,这里的释放逻辑其实大部分情况下是不一样的,方法调用也不一定一样,我只是偷懒而已
    public void attack() {
        attack.release();
    }
    public void dodge() {
        dodge.release();
    }
    public void skill() {
        skill.release();
    }
}

BOSS实现类

public class MartialGod extends Boss{
    public MartialGod(){
        this.name="MartialGod";
    }
}

技能接口

public interface ISkill {
    void release();
}

具体实现

//技能,剑舞
public class JianWu implements ISkill{
    @Override
    public void release() {
        System.out.println("释放剑舞");
    }
}

攻击接口

public interface IAttack {
    void release();
}

具体实现

//普攻,扫腿
public class SaoTui implements IAttack{
    @Override
    public void release() {
        System.out.println("释放扫腿");
    }
}

闪避接口

public interface IDodge {
    void release();
}

具体实现

//闪避,后跳
public class HouTiao implements IDodge{
    @Override
    public void release() {
        System.out.println("释放后跳");
    }
}

测试

 @Test
    public void test()
    {
        Boss boss=new MartialGod();
        boss.setAttack(new SaoTui()).setDodge(new HouTiao()).setSkill(new JianWu());
        boss.attack();
        boss.dodge();
        boss.skill();
    }

测试结果

释放扫腿
释放后跳
释放剑舞

进一步案例

这个BOSS看起来就不太行的样子,正好我最近也看了设计模式中的状态模式,我们来对BOSS做一些加强,我们将BOSS设计为有两个阶段,两条独立血量,第一阶段血量归零则回满血进入第二阶段。第一阶段和第二阶段使用不同技能组。使用状态模式将BOSS的两个阶段独立出来。具体我们来看代码,这里我只介绍一下增加和修改的代码。

首先我们分别添加一个普攻,一个闪避,一个技能用于BOSS二阶段释放

//普攻,顺劈斩
public class ShunPiZhan implements IAttack{
    @Override
    public void release() {
        System.out.println("释放顺劈斩");
    }
}
//闪避,闪现
public class ShanXian implements IDodge{
    @Override
    public void release() {
        System.out.println("释放闪现");
    }
}

//技能,万剑天来
public class WanJianTianLai implements ISkill{
    @Override
    public void release() {
        System.out.println("释放万剑天来");
    }
}

然后我们修改一下BOSS类,将对应方法放入状态类中实现,并且添加一些额外的成员变量

@Data
//BOSS超类
public abstract class Boss {
    protected String name;
    //Boss血量
    protected int bloodVolume;
    //Boss二阶段血量
    protected int secondBloodVolume;
    //动作组
    protected IAttack attack;
    protected IDodge dodge;
    protected ISkill skill;
    //目前BOSS所处阶段
    protected Stage stage;
}

BOSS实现类

public class MartialGod extends Boss{
    public MartialGod(int Volume,int SecondVolume){
        this.name="MartialGod";
        this.bloodVolume=Volume;
        this.secondBloodVolume=SecondVolume;
        stage=new FirstStage(this);
    }
}

状态抽象类

public abstract class Stage {
    protected Boss boss;
    public abstract void attack();
    public abstract void dodge();
    public abstract void skill();
    //boss被攻击掉血
    public abstract void attacked(int attack);
}

状态实现类,实际上这里的构造函数不应该固定给技能组,不利于扩展,应该在Boss类中添加方法,然后具体实现类实现安装技能组对应函数,这里构造函数直接调用对应的技能组,这样有利于扩展,这里偷懒懒得改了

//BOSS一阶段
public class FirstStage extends Stage{

    public FirstStage(Boss boss){
        this.boss=boss;
        this.boss.setAttack(new SaoTui());
        this.boss.setDodge(new HouTiao());
        this.boss.setSkill(new JianWu());
    }

    //实际上攻击等操作可能会复杂,这里我全部简化了
    @Override
    public void attack() {
        boss.attack.release();
    }

    @Override
    public void dodge() {
        boss.dodge.release();
    }

    @Override
    public void skill() {
        boss.skill.release();
    }

    @Override
    public void attacked(int attack) {
        boss.bloodVolume-=attack;
        if(boss.bloodVolume<0){
            boss.bloodVolume=0;
        }
        System.out.println("BOSS一阶段被攻击,受到伤害:"+attack+",Boss剩余血量:"+boss.bloodVolume);
        if(boss.bloodVolume==0){
            System.out.println("BOSS血量归零,进入二阶段");
            boss.stage=new SecondStage(boss);
        }
    }
}
//BOSS二阶段
public class SecondStage extends Stage{
    public SecondStage(Boss boss){
        this.boss=boss;
        this.boss.setAttack(new ShunPiZhan());
        this.boss.setDodge(new ShanXian());
        this.boss.setSkill(new WanJianTianLai());
    }
    //实际上攻击等操作可能会复杂,这里我全部简化了
    @Override
    public void attack() {
        boss.attack.release();
    }

    @Override
    public void dodge() {
        boss.dodge.release();
    }

    @Override
    public void skill() {
        boss.skill.release();
    }

    @Override
    public void attacked(int attack) {
        boss.secondBloodVolume-=attack;
        if(boss.secondBloodVolume<0){
            boss.secondBloodVolume=0;
        }
        System.out.println("BOSS二阶段被攻击,受到伤害:"+attack+",Boss剩余血量:"+boss.secondBloodVolume);
        if(boss.secondBloodVolume==0){
            System.out.println("BOSS二阶段血量归零,战斗胜利");
            //后面应该有结算函数,这里不写啦
        }
    }
}

测试

@Test
    public void test()
    {
        Boss boss=new MartialGod(100,200);
        //BOSS释放招式
        boss.getStage().attack();
        boss.getStage().dodge();
        boss.getStage().skill();
        //攻击BOSS
        boss.getStage().attacked(60);
        boss.getStage().attacked(60);
        //BOSS二阶段释放技能
        boss.getStage().attack();
        boss.getStage().dodge();
        boss.getStage().skill();
        //攻击BOSS
        boss.getStage().attacked(60);
        boss.getStage().attacked(60);
        boss.getStage().attacked(60);
        boss.getStage().attacked(60);
    }

测试结果


释放扫腿
释放后跳
释放剑舞
BOSS一阶段被攻击,受到伤害:60,Boss剩余血量:40
BOSS一阶段被攻击,受到伤害:60,Boss剩余血量:0
BOSS血量归零,进入二阶段
释放顺劈斩
释放闪现
释放万剑天来
BOSS二阶段被攻击,受到伤害:60,Boss剩余血量:140
BOSS二阶段被攻击,受到伤害:60,Boss剩余血量:80
BOSS二阶段被攻击,受到伤害:60,Boss剩余血量:20
BOSS二阶段被攻击,受到伤害:60,Boss剩余血量:0
BOSS二阶段血量归零,战斗胜利

这样整个程序也就写完了,这只是一个突发奇想的简单例子,与实际开发还是有很大区别的,主要还是练习一下设计模式的使用。

总结

可以看出,策略模式的优势就在于将算法族和应用者隔离开,应用者可以很方便的切换算法。但是缺点也很明显,就是会导致类数量的爆炸,尤其是程序复杂时。像我这个简单的例子都已经有10多个类了。而且对应用者要求高,应用者必须要知道每个算法,不符合迪米特原则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值