JavaFX中基于Projectile类型复制子弹实例,避免冗余分支判断
解决JavaFX游戏中根据子弹类型生成克隆实例的问题
嘿,这个场景太常见了!想要不用一堆if-else判断就能生成对应子弹的实例,原型设计模式绝对是你的最佳选择——它能让每个子弹子类自己负责创建自己的副本,完美符合开闭原则,后续加新子弹类型也不用改Player的代码。
下面给你两种具体实现方案,你可以根据自己的需求选:
方案一:自定义抽象创建方法(推荐,灵活可控)
首先在你的Projectile抽象类中定义一个抽象的创建副本方法,让每个子弹子类自己实现这个方法来返回自身的实例:
public abstract class Projectile { // 这里放你的通用字段(比如速度、位置)和方法 public abstract Projectile createCopy(); // 核心抽象方法 }
然后以SingleShot为例,子类实现这个方法,按需复制字段(如果是值类型直接赋值,引用类型要做深拷贝):
public class SingleShot extends Projectile { private int damage; private double speed; // 构造器、getter/setter等方法 @Override public Projectile createCopy() { SingleShot newShot = new SingleShot(); // 复制当前实例的属性到新实例 newShot.damage = this.damage; newShot.speed = this.speed; // 如果有引用类型的字段,比如自定义的Vector2D位置,要new一个新对象赋值,避免浅拷贝问题 return newShot; } }
最后在Player类里,你只需要调用这个方法就能生成对应子弹的实例,完全不用判断类型:
public class Player { private Projectile currentProjectileType; // 这里存储的是比如SingleShot的实例 // 按钮按下触发的方法 public void onFireButtonPressed() { if (currentProjectileType != null) { Projectile newBullet = currentProjectileType.createCopy(); // 把newBullet添加到游戏场景、设置初始位置等逻辑 // ... } } }
方案二:利用Java的Cloneable接口
如果你想复用Java自带的克隆机制,可以让Projectile实现Cloneable接口,但要注意Cloneable本身的坑(比如默认是浅拷贝,需要重写clone方法处理引用类型):
public abstract class Projectile implements Cloneable { // 通用字段和方法 // 封装clone方法,避免外部处理异常 public Projectile createCopy() { try { return (Projectile) this.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException("Failed to clone projectile instance", e); } } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // 默认浅拷贝 } }
然后在子类中重写clone方法,处理自定义字段的深拷贝:
public class SingleShot extends Projectile { private int damage; private Vector2D direction; // 假设是自定义的引用类型 @Override protected Object clone() throws CloneNotSupportedException { SingleShot copy = (SingleShot) super.clone(); // 值类型直接复制 copy.damage = this.damage; // 引用类型要创建新实例,避免和原对象共享引用 copy.direction = new Vector2D(this.direction.getX(), this.direction.getY()); return copy; } }
Player类的调用逻辑和方案一完全一样,直接调用createCopy()即可。
为什么这两种方案比if-else好?
- 扩展性强:新增任何子弹类型(比如
SpreadShot、LaserBeam),只需要在子类里实现createCopy或重写clone,不用修改Player类的代码。 - 代码更简洁:不用写一堆
if (currentType instanceof SingleShot) { ... } else if (...)的判断逻辑,维护起来轻松很多。 - 符合开闭原则:对扩展开放,对修改关闭,这是面向对象设计的核心原则之一。
内容的提问来源于stack exchange,提问作者Tommy
相关产品推荐
相关产品推荐

