TypeScript中如何限制Set仅保留同一Spell子类的单个实例?
解决方案
方案1:重写Spell类的equals()和hashCode()方法
Set的去重逻辑完全依赖元素的equals()和hashCode()方法,默认的Object实现是比较对象引用,所以不同实例会被判定为不同元素。我们可以让这两个方法基于类的类型来判断,这样同一子类的所有实例都会被视为相同元素:
public abstract class Spell { @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; // 若Spell有需要参与判定的属性,可在此补充逻辑 return true; } @Override public int hashCode() { return getClass().hashCode(); } }
修改后,同一子类的不同实例会被Set判定为重复,不会被多次添加。
方案2:将Spell子类实现为单例
如果每个法术类型本身只应该存在一个实例,直接把Fireball、Lightning做成单例,这样每次添加的都是同一个对象引用,Set自然会自动去重:
饿汉式单例实现
public class Fireball extends Spell { private static final Fireball INSTANCE = new Fireball(); private Fireball() {} public static Fireball getInstance() { return INSTANCE; } } public class Lightning extends Spell { private static final Lightning INSTANCE = new Lightning(); private Lightning() {} public static Lightning getInstance() { return INSTANCE; } }
使用时调用Fireball.getInstance()获取实例添加到Set,无论调用多少次,都是同一个对象,不会出现重复存储的问题。
方案3:用枚举类替代子类
如果法术类型是固定的有限个(比如只有Fireball和Lightning),用枚举实现是最简洁的方案——枚举天然是单例,且自带正确的equals()和hashCode()实现:
public enum Spell { FIREBALL, LIGHTNING; // 可添加法术的核心方法,比如施法逻辑 public abstract void cast(); @Override public void cast() { switch(this) { case FIREBALL: System.out.println("释放火球术"); break; case LIGHTNING: System.out.println("释放闪电术"); break; } } }
此时Character的spells属性定义为Set<Spell>,直接添加Spell.FIREBALL即可,完全不会出现重复问题。
内容的提问来源于stack exchange,提问作者Michael Moreno
相关产品推荐
相关产品推荐

