打破长开关

时间:2016-04-20 12:59:08

标签: java refactoring

我有这段代码:

public void addSkillXp(SkillType attribute, int value) {
    final SkillDatabaseEntity skillDatabaseEntity = skillValueCache.getEntity();

    switch (attribute) {
        case TWO_HANDED_CRUSHING_WEAPONS:
            skillDatabaseEntity.setTwoHandedCrushingWeaponsXp(value);

            skillMapper.addTwoHandedCrushingWeaponsXp(userEntity.getId(), value);
            break;
        case ONE_HANDED_CRUSHING_WEAPONS:
            skillDatabaseEntity.setOneHandedCrushingWeaponsXp(value);

            skillMapper.addOneHandedCrushingWeaponsXp(userEntity.getId(), value);
            break;
        case TWO_HANDED_AXES:
            skillDatabaseEntity.setTwoHandedAxesXp(value);

            skillMapper.addTwoHandedAxesXp(userEntity.getId(), value);
            break;
        case ONE_HANDED_AXES:
            skillDatabaseEntity.setOneHandedAxesXp(value);

            skillMapper.addOneHandedAxesXp(userEntity.getId(), value);
            break;
        case THROWING_WEAPONS:
            skillDatabaseEntity.setThrowingWeaponsXp(value);

            skillMapper.addThrowingWeaponsXp(userEntity.getId(), value);
            break;
        case FISTFIGHT:
            skillDatabaseEntity.setFistfightXp(value);

            skillMapper.addFistfightXp(userEntity.getId(), value);
            break;
        ...
}

开关继续进行20多例。 SkillDatabaseEntity是一个简单的DAO类:

public class SkillDatabaseEntity {

    private int twoHandedCrushingWeaponsXp;
    private int oneHandedCrushingWeaponsXp;
    private int twoHandedAxesXp;
    private int oneHandedAxesXp;
    private int throwingWeaponsXp;
    private int fistfightXp;
    private int longswordsXp;
    private int shortswordsXp;
    private int polearmsXp;
    private int daggersXp;
    private int longbowsXp;
    private int showrtbowsXp;
    private int crossbowsXp;
    private int lightArmorXp;
    private int heavyArmorXp;
    private int robeArmorXp;
    private int armorlessDefenseXp;
    private int shieldDefenseXp;
    private int staffsXp;
    private int wandsXp;
    private int spectresXp;
    private int scavengingXp;
    private int cookingXp;

    public int getTwoHandedCrushingWeaponsXp() {
        return twoHandedCrushingWeaponsXp;
    }

    public void setTwoHandedCrushingWeaponsXp(int twoHandedCrushingWeaponsXp) {
        this.twoHandedCrushingWeaponsXp = twoHandedCrushingWeaponsXp;
    }

    public int getOneHandedCrushingWeaponsXp() {
        return oneHandedCrushingWeaponsXp;
    }

    public void setOneHandedCrushingWeaponsXp(int oneHandedCrushingWeaponsXp) {
        this.oneHandedCrushingWeaponsXp = oneHandedCrushingWeaponsXp;
    }

    public int getTwoHandedAxesXp() {
        return twoHandedAxesXp;
    }

    public void setTwoHandedAxesXp(int twoHandedAxesXp) {
        this.twoHandedAxesXp = twoHandedAxesXp;
    }

    public int getOneHandedAxesXp() {
        return oneHandedAxesXp;
    }

    public void setOneHandedAxesXp(int oneHandedAxesXp) {
        this.oneHandedAxesXp = oneHandedAxesXp;
    }

    public int getThrowingWeaponsXp() {
        return throwingWeaponsXp;
    }

    public void setThrowingWeaponsXp(int throwingWeaponsXp) {
        this.throwingWeaponsXp = throwingWeaponsXp;
    }
    ...
}

我需要添加removeSkillXp,但我真的想避免这个巨大的开关,如果我在这里,我也希望改进那个旧的scwitch。我怎么能这样做?

我的计划是创建一个像这样的新类:

SkillModifier:

  • 增加经验(UserEntity,value)
  • 减少经验(UserEntity,value)
  • getExperience(UserEntity,value)
  • getSupportedSkillType()

为交换机中的每个案例创建此类的实例,将实例添加到地图中(这可以通过Spring DI轻松完成)并使用以下内容:

public void addSkillXp(SkillType attribute, int value) {
    skillMap.get(attribute).increaseExperience(userEntity, value);
}

这可以吗?或者有更好的模式吗?

2 个答案:

答案 0 :(得分:1)

整个开关看起来多余,因为每个案例都做同样的事情。为什么不创建一个抽象类武器,它有一个方法increaseXP并且被每个武器类扩展(2h等)。
通过这种方式,实现在抽象类中,其他子类只调用.increaseXP。

顺便说一下数据库类似乎没必要,只需为每个玩家保留一份武器列表/数组。

更多背景信息请参阅:

https://sourcemaking.com/refactoring/replace-conditional-with-polymorphism

答案 1 :(得分:1)

如果将功能从代码移动到对象中,事情会变得容易多了。

例如:

enum SkillType {
    TWO_HANDED_CRUSHING_WEAPONS {
        @Override
        void updateEntity(SkillDatabaseEntity entity, int value) {
            entity.setTwoHandedCrushingWeaponsXp(value);
        }

        @Override
        void mapSkill(SkillMapper mapper, int userId, int value) {
            mapper.addTwoHandedCrushingWeaponsXp(userId, value);

        }
    },
    ONE_HANDED_CRUSHING_WEAPONS {
        @Override
        void updateEntity(SkillDatabaseEntity entity, int value) {
            entity.addOneHandedCrushingWeaponsXp(value);
        }

        @Override
        void mapSkill(SkillMapper mapper, int userId, int value) {
            mapper.addOneHandedCrushingWeaponsXp(userId, value);

        }
    },
    TWO_HANDED_AXES {
        @Override
        void updateEntity(SkillDatabaseEntity entity, int value) {
            entity.setTwoHandedAxesXp(value);
        }
        @Override
        void mapSkill(SkillMapper mapper, int userId, int value) {
            mapper.addTwoHandedAxesXp(userId, value);

        }
    };

    abstract void updateEntity(SkillDatabaseEntity entity, int value);

    abstract void mapSkill(SkillMapper mapper, int userId, int value);
}

public void addSkillXp(SkillType skill, int value) {
    final SkillDatabaseEntity skillDatabaseEntity = skillValueCache.getEntity();
    skill.updateEntity(skillDatabaseEntity, value);
    skill.mapSkill(skillMapper, userEntity.getId(), value);
}

此处addSkillXp只变成了三行代码。

另一个优雅的好处是,所有技能相关的代码都在同一个enum