策略模式——在游戏设计中的思路

阅读本文你可以:
1.带入游戏角色设计实例,了解策略模式
2.分析该实例,进一步体会策略模式的优势

1.什么是策略模式

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

定义太生硬看不太懂不要紧,下面通过一个游戏设计的实例,很快就可以理解其中的精神。

2.结合实例分析策略模式

你是一款格斗游戏开发人员,现在需要对游戏角色和角色行为做设计。产品同学对你说,现在需要剑士和战士两种不同的角色,角色可以进行物理攻击操作,需求简单的不行,你分分钟就写出了几个类:

1.英雄类,所有角色都继承于这个抽象类。

public abstract class Hero{
    void attack(){
        System.out.println("物理普通攻击");
    }
    void display(){}
}

2.战士和法师两个子类

public class Worrier extends Hero {
    @Override
    void display(){
        System.out.println("我是一名战士");
    }
}
public class Sword extends Hero {
    @Override
    void display(){
        System.out.println("我是一名剑士");
    }
}

写完之后,产品同学走过来了,告诉我们,现在需要多加入几种角色,比如法师和刺客,法师的attack攻击方法是魔法攻击,刺客的attack攻击方法是穿刺攻击,你想了想,那我重写这两个角色的attack()方法不就ok了,没什么大问题。

public class Magic extends Hero {
	@Override
	void attack() {
		System.out.println("造成魔法攻击");
	}
    @Override
    void display(){
        System.out.println("我是一名法师");
    }
}

写完之后,你去吃饭的时候路过了产品同学,他告诉你预计一周更新一次角色。你开始问题有点棘手了,继承重写这样的方式貌似不太合适,因为你每一次新角色的加入和老角色的改动,你都需要调整你重写的attack代码,那接口是否合适呢?我把物理攻击、魔法攻击、穿刺攻击都写成接口,不同的角色只需要实现不同的接口就可以了。

public class Magic implement magicAttack {
	void attack() {
		System.out.println("造成魔法攻击");
	}
    @Override
    void display(){
        System.out.println("我是一名法师");
    }
}

你意识到了,接口显然是错误的,因为你需要实现每一个角色的attack方法,代码无法重用了。在你思考解决办法的时候,你收到了产品同学发来的新添加角色表,有10种新角色,一部分造成魔法攻击,一部分物理攻击,一些角色根据情况使用魔法攻击或者物理攻击,,你人傻了,之前的设计思路是完全不能用了。

谢天谢地,你这时候想到了策略模式

你把attack()方法拆解了出来,之前attack()是父类Hero的一个方法,现在attack是一个抽象类,有魔法攻击、物理攻击等子类。
1.攻击类

接口:
public interface Attack {
    void attackBehavior();
}
魔法攻击:
public class MagicAttack implements Attack {
    @Override
    public void attackBehavior() {
        System.out.println("魔法攻击");
    }
}
物理攻击:
public class NormalAttack implements Attack  {
    @Override
    public void attackBehavior() {
        System.out.println("物理攻击");
    }
}

2.英雄类
hero类的attck对象通过继承传给子类,子类只需要调用自己的attack方法即可。

public abstract class Hero{
    Attack attack;

    public void attack(){
        attack.attackBehavior();
    }

    public void setAttack(Attack at) {
        System.out.println("改变攻击行为");
        this.attack = at;
    }

    public void display(){}
}

法师和战士类使用继承来的attck对象调用设计要求的物理攻击或者魔法攻击对象。

public class Worrier extends Hero {
    public Worrier(){
        attack = new NormalAttack();
    }
    @Override
    public void display(){
        System.out.println("我是一名战士");
    }
}
public class Magic extends Hero {
    public Magic(){
        attack = new MagicAttack();
    }
    @Override
    public void display(){
        System.out.println("我是一名法师");
    }
}

最后一个要求,那如何做到动态改变一个角色的行为呢?比如一个角色既可以物理攻击也可以魔法攻击,那我们只需要给setAttack方法传不同的对象就可以做到了。
下面是测试代码

public class StrategyTest {
    public static void main(String[] args){
        Hero worrier = new Worrier();
        worrier.attack();
        worrier.setAttack(new MagicAttack());
        worrier.attack();
    }
}

输出为:
在这里插入图片描述

3.总结

通过上面的实例,我们把绑定在角色上的attack方法拆分开了,好处是,首先在增加新角色时我们对于attack方法做到了代码复用,其次,我们如果要增加新的角色行为也很方便,最重要的,我们可以动态的选择角色的行为。

策略模式的优点:
让算法(或者说行为、方法),独立于对象之外,脱离继承体系的限制。
具体体现:
1.算法之间可以自由的切换
2.避免了使用很多重的条件判断
3.非常方便进行扩展
策略模式的缺点:
1.会多出很多额外的策略类,这些类的编译运行是额外开销,而且类越来越多代码会难以理解。
2.所有策略类都需要对外暴露。

猜你喜欢

转载自blog.csdn.net/qq_42685588/article/details/103576562