如何用泛型与多态优化C#中Deck类的卡牌填充逻辑?
优化Deck.populate方法:用泛型+多态消除重复代码
先看你原来的代码大概是这样的(重复的循环逻辑):
public class Deck { private List<Card> cards = new ArrayList<>(); public void populate() { for (int i = 0; i < 10; i++) { cards.add(new Club()); } for (int i = 0; i < 10; i++) { cards.add(new Diamond()); } for (int i = 0; i < 10; i++) { cards.add(new Heart()); } for (int i = 0; i < 10; i++) { cards.add(new Spike()); } } }
下面是两种基于泛型和多态的优化方案,核心思路是把重复的循环逻辑抽离,统一处理所有Card子类:
方案1:用Supplier实现类型安全的实例创建(推荐)
利用Supplier<? extends Card>泛型限定,确保只有Card的子类实例能被生成,同时避免反射的异常处理,编译时就能检查类型:
import java.util.List; import java.util.ArrayList; import java.util.function.Supplier; public class Deck { private List<Card> cards = new ArrayList<>(); // 把所有卡牌类型的实例生成器放在一个列表里 private static final List<Supplier<? extends Card>> CARD_SUPPLIERS = List.of( Club::new, Diamond::new, Heart::new, Spike::new ); private static final int CARDS_PER_TYPE = 10; public void populate() { cards.clear(); // 按需清空旧卡牌 for (Supplier<? extends Card> cardSupplier : CARD_SUPPLIERS) { for (int i = 0; i < CARDS_PER_TYPE; i++) { // 多态特性:所有子类实例都能直接加入Card列表 cards.add(cardSupplier.get()); } } } }
方案2:用Class对象+反射实现
如果你的Card子类都有公共无参构造,可以用Class<? extends Card>泛型限定类型,通过反射创建实例:
import java.util.List; import java.util.ArrayList; public class Deck { private List<Card> cards = new ArrayList<>(); // 存储所有Card子类的Class对象 private static final List<Class<? extends Card>> CARD_TYPES = List.of(Club.class, Diamond.class, Heart.class, Spike.class); private static final int CARDS_PER_TYPE = 10; public void populate() { cards.clear(); for (Class<? extends Card> cardType : CARD_TYPES) { try { for (int i = 0; i < CARDS_PER_TYPE; i++) { // 反射创建实例,多态加入列表 cards.add(cardType.getDeclaredConstructor().newInstance()); } } catch (Exception e) { throw new RuntimeException("Failed to create card of type: " + cardType.getName(), e); } } } }
优化点说明
- 多态:所有Club/Diamond等子类都继承自Card,所以可以统一添加到
List<Card>中,无需单独处理每个类型 - 泛型:通过
Supplier<? extends Card>或Class<? extends Card>限定类型范围,确保只有Card的子类能被加入集合,避免类型错误 - 消除重复:新增卡牌类型时,只需要在列表里加一行代码,不用再写重复的for循环
注意事项
- 如果Card子类需要带参数的构造方法,Supplier方案可以灵活调整,比如
() -> new Club("参数1", 2) - Supplier方案是编译时检查,比反射更安全,优先推荐使用
内容的提问来源于stack exchange,提问作者Finley Adams
相关产品推荐
相关产品推荐

