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

Java中简化Campaign与Character相似类操作的最佳实践咨询

解决方案:基于抽象类+接口的代码复用方案

针对你遇到的Campaign和Character类代码冗余问题,推荐用抽象类封装共享逻辑+接口定义差异字段契约的方案,既保留两个类的独立性,又能最大化复用代码,还支持后续扩展。

核心思路

  1. 用抽象类把ID、Owner、Name这些共享字段和通用操作(比如JSON序列化/反序列化的通用部分)封装起来,把差异字段的处理交给子类。
  2. 定义接口统一差异字段的访问方式,让两个类通过接口暴露差异字段,通用代码只需要调用接口方法,不用关心具体字段名。
  3. 写一个通用管理器类,基于抽象类和接口实现加载、保存等通用操作,彻底消除重复代码。

具体实现代码

1. 抽象类封装共享逻辑

创建DndEntity抽象类,负责处理所有共享字段和通用JSON操作:

import org.json.JSONObject;
import java.io.FileWriter;
import java.io.IOException;

public abstract class DndEntity {
    protected String id;
    protected String owner;
    protected String name;

    // 共享字段的getter/setter
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getOwner() { return owner; }
    public void setOwner(String owner) { this.owner = owner; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    // 通用保存方法,子类只需实现差异字段的序列化
    public void saveToJson(String filePath) {
        JSONObject json = new JSONObject();
        // 序列化共享字段
        json.put("id", id);
        json.put("owner", owner);
        json.put("name", name);
        // 交给子类处理差异字段
        addVariantFields(json);
        // 写入文件的通用逻辑
        try (FileWriter writer = new FileWriter(filePath)) {
            writer.write(json.toString(4));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 抽象方法:子类实现差异字段的序列化
    protected abstract void addVariantFields(JSONObject json);
}

2. 接口定义差异字段契约

创建DndEntityWithAssociates接口,统一差异字段的访问方式:

import java.util.List;

public interface DndEntityWithAssociates {
    // 获取"Edition/Race"这类变体属性
    String getVariantAttribute();
    void setVariantAttribute(String value);

    // 获取关联实体列表(Campaign的Characters / Character的Campaigns)
    List<? extends DndEntity> getAssociatedEntities();
    void setAssociatedEntities(List<? extends DndEntity> entities);
}

3. 子类实现接口并映射字段

Campaign类

import org.json.JSONArray;
import org.json.JSONObject;
import java.util.List;

public class Campaign extends DndEntity implements DndEntityWithAssociates {
    private String edition;
    private List<Character> characters;

    @Override
    protected void addVariantFields(JSONObject json) {
        json.put("edition", edition);
        // 序列化关联的角色列表(仅存ID避免循环引用)
        JSONArray charsArray = new JSONArray();
        for (Character c : characters) {
            charsArray.put(c.getId());
        }
        json.put("characters", charsArray);
    }

    @Override
    public String getVariantAttribute() {
        return edition;
    }

    @Override
    public void setVariantAttribute(String value) {
        this.edition = value;
    }

    @Override
    public List<? extends DndEntity> getAssociatedEntities() {
        return characters;
    }

    @Override
    public void setAssociatedEntities(List<? extends DndEntity> entities) {
        this.characters = (List<Character>) entities;
    }

    // 后续扩展的特有方法
    public void addCharacter(Character character) {
        characters.add(character);
    }
}

Character类

import org.json.JSONArray;
import org.json.JSONObject;
import java.util.List;

public class Character extends DndEntity implements DndEntityWithAssociates {
    private String race;
    private List<Campaign> campaigns;

    @Override
    protected void addVariantFields(JSONObject json) {
        json.put("race", race);
        // 序列化关联的战役列表
        JSONArray campaignsArray = new JSONArray();
        for (Campaign c : campaigns) {
            campaignsArray.put(c.getId());
        }
        json.put("campaigns", campaignsArray);
    }

    @Override
    public String getVariantAttribute() {
        return race;
    }

    @Override
    public void setVariantAttribute(String value) {
        this.race = value;
    }

    @Override
    public List<? extends DndEntity> getAssociatedEntities() {
        return campaigns;
    }

    @Override
    public void setAssociatedEntities(List<? extends DndEntity> entities) {
        this.campaigns = (List<Campaign>) entities;
    }

    // 后续扩展的特有方法
    public void joinCampaign(Campaign campaign) {
        campaigns.add(campaign);
    }
}

4. 通用管理器类

写一个DndEntityManager,实现通用的加载、保存操作:

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class DndEntityManager {
    // 通用加载方法,支持加载Campaign或Character
    public <T extends DndEntity & DndEntityWithAssociates> T loadEntity(Class<T> clazz, String filePath) {
        try (FileReader reader = new FileReader(filePath)) {
            JSONObject json = new JSONObject(new JSONTokener(reader));
            T entity = clazz.getDeclaredConstructor().newInstance();

            // 设置共享字段
            entity.setId(json.getString("id"));
            entity.setOwner(json.getString("owner"));
            entity.setName(json.getString("name"));

            // 设置变体属性
            String variantKey = clazz == Campaign.class ? "edition" : "race";
            entity.setVariantAttribute(json.getString(variantKey));

            // 加载关联实体(示例仅处理ID,实际可根据ID从对应文件加载)
            String associateKey = clazz == Campaign.class ? "characters" : "campaigns";
            JSONArray associateIds = json.getJSONArray(associateKey);
            List<DndEntity> associates = new ArrayList<>();
            // 这里可以根据ID加载对应的实体,比如如果是Campaign,加载Character对象
            // 示例省略具体加载逻辑
            entity.setAssociatedEntities(associates);

            return entity;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 通用保存方法
    public <T extends DndEntity> void saveEntity(T entity, String filePath) {
        entity.saveToJson(filePath);
    }
}

扩展说明

  • 如果后续要给Campaign加新字段(比如setting),或者给Character加characterClass,只需要在对应类里添加字段,修改addVariantFields方法即可,完全不影响抽象类和管理器类。
  • 两个类各自的特有方法可以自由扩展,完全保留独立性,不会出现合并成通用类的扩展性问题。

内容的提问来源于stack exchange,提问作者Patrick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.04 15:04:51