You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:44:55