- 问题描述
- 实现游戏的不同角色
- 解决方案
- 存在问题
- 策略模式
- 总结
问题描述
实现游戏的不同角色
某游戏中Queen,King,Knight这3种角色,每种角色都有使用武器行为,设计这三个类,提高代码的重用性和可维护性。
解决方案
Queen,King,Knight这三个角色都是角色,都可以move,可以stop,因此可以设计一个Character抽象类,抽取三个角色的共同行为,减少代码的重复性,Character定义如下:
public abstract class Character {
public void move() { // do move action }
public void stop() { // do stop action }
public void useWeapon() { // do use sword}
}
三个角色继承于Character这个抽象类, 但是如果Queen用的武器是枪呢? 可以在子类重写该方法啊!
public class Queen() extends Character {
@Override
public void useWeapon() {
// do use gun
}
}
public class King() extends Character { ... }
public class Knight() extends Character { ... }
但是还有一个问题,如果我新增了其他角色,当然继承于Character,如果新增的这个类没有使用武器的行为呢?
还有另外一种解决方法,将容易改变的行为抽象成一个接口。
public abstract class Character {
public void move() { // do move action }
public void stop() { // do stop action }
}
public interface WeaponBehavior {
void useWeapon();
}
public class King extends Character implements WeaponBehavior {
public void useWeapon() { // do use sword }
}
public class Queen extends Character implements WeaponBehavior {
public void useWeapon() { // do use sword }
}
public class Knight implements WeaponBehavior extends Character {
public void useWeapon() { // do use gun }
}
上面接口的方式看上去挺合理的,但是角色一多就会发现在useWeapon方法中会出现大量的代码重复,虽然可以将重复代码抽取出来放到其他地方,但是这样就破坏了类的封装性。
存在问题
- 用继承的方法会让代码不灵活,不支持子类中没有该方法的行为,如果修改了父类的方法会让所有类都产生影响
- 使用接口的方法增加了重复代码
- 上面两种方法还有一个缺点,对象的行为在编译时候已经确定,无法在运行时候更改
- 如果对象的使用武器行为有所改变,改其中的代码将是一件非常痛苦的事情
策略模式
考虑到不同对象使用不同的武器,而且使用武器方法会不断改变,最好将经常改变的东西封装起来,以后一旦有需要修改的,则只需要修改封装部分就可以,而其他模块不会受到影响。策略模式的核心思想就是把变化的行为(算法)封装,让他们可以相互替换,这个模式可以让变化的算法独立于使用这些行为(算法)的客户。具体看下面的实现:
public interface WeaponBehavior {
void useWeapon();
}
public class SwordBehavior implements WeaponBehavior {
@Override
public void useWeapon() { // do sword behavior }
}
public class GunBehavior implements WeaponBehavior {
@Override
public void useWeapon() { // do gun behavior }
}
public abstract class Character {
WeaponBehavior weaponBehavior;
public void move() { // do move action }
public void stop() { // do stop action }
public void useWeapon() {
weaponBehavior.useWeapon();
}
public setWeaponBehavior(WeaponBehavior weaponBehavior) {
this.weaponBehavior = weaponBehavior;
}
}
public class King extends Character {
public King() {
weaponBehavior = new GunBehavior();
}
}
public class Queen extends Character {
public Queen() {
weaponBehavior = new SwordBehavior();
}
}
如上代码所示,将经常需要改变的行为封装成类,有如下好处:
- 当需求变动时,只需修改封装的类,对于客户端代码可以保持原样,系统更具有弹性
- 当程序运行时候,可以调用setter来改变对象的行为
- 当新增一些其他行为的时候,不会影响到原有的对象的行为
总结
策略模式适用于有多类似对象,这些对象又有类似行为,并且行为会不断发生变化这样的场景。策略模式将算法封装起来,让算法之间可以相互替换,并且这种替换对使用算法的客户来说是独立的。
策略模式体现了软件设计的原则:
- 找出应用中可能变化的地方,把他们独立出来,不要和那些需求不变的代码混在一起
- 要针对接口编程,不要对实现编程
- 多用组合,少用继承 : 在系统中使用组合可以让系统有更大的弹性,不仅可以应对算法的变化,更可以在运行时动态改变行为
时间: 2024-10-02 10:23:09