如何在循环中初始化特定子类?Operator子类实例化优化方案咨询
嘿,这个场景我之前做业务的时候也遇到过,原来用一堆if-else判断标识来实例化子类,维护起来巨麻烦。其实有几种更优雅、可扩展的实现方式,给你分享一下:
首先先明确一下基础的类结构,方便后续示例参考:
// 父类 abstract class Operator { // 每个子类拥有自己的标识,这里用抽象方法让子类实现 public abstract String getType(); } class Conjunction extends Operator { public static final String TYPE = "AND"; @Override public String getType() { return TYPE; } } class Disjunction extends Operator { public static final String TYPE = "OR"; @Override public String getType() { return TYPE; } }
方案1:枚举驱动的工厂模式(最推荐)
这种方式把标识和子类的实例化逻辑绑定在枚举里,完全避免硬编码判断,新增子类只需要扩展枚举即可,完美符合开闭原则:
// 定义枚举,每个枚举项对应一个Operator子类 enum OperatorType { CONJUNCTION("AND") { @Override public Operator createInstance() { return new Conjunction(); } }, DISJUNCTION("OR") { @Override public Operator createInstance() { return new Disjunction(); } }; private final String typeStr; OperatorType(String typeStr) { this.typeStr = typeStr; } // 抽象方法,每个枚举项实现自己的实例化逻辑 public abstract Operator createInstance(); // 根据标识字符串找到对应的枚举项 public static OperatorType fromTypeStr(String typeStr) { for (OperatorType type : values()) { if (type.typeStr.equals(typeStr)) { return type; } } throw new IllegalArgumentException("Unknown operator type: " + typeStr); } } // 你的selectOperator方法可以简化成这样 public Operator selectOperator(String typeStr) { return OperatorType.fromTypeStr(typeStr).createInstance(); } // 循环初始化特定子类的例子:比如创建5个Conjunction实例 List<Operator> conjunctions = new ArrayList<>(); for (int i = 0; i < 5; i++) { conjunctions.add(OperatorType.CONJUNCTION.createInstance()); }
这个方案的优势是类型安全(不会传错标识字符串)、易维护(新增子类只需要加枚举项),而且不需要修改已有的select方法,扩展性拉满。
方案2:Map映射表(轻量灵活)
如果不想用枚举,也可以用一个静态Map来存储标识和对应的实例化Supplier,查找效率是O(1),代码也很简洁:
import java.util.Map; import java.util.function.Supplier; import java.util.HashMap; class OperatorFactory { // 静态初始化Map,绑定标识和子类构造函数引用 private static final Map<String, Supplier<Operator>> OPERATOR_SUPPLIERS = new HashMap<>(); static { OPERATOR_SUPPLIERS.put(Conjunction.TYPE, Conjunction::new); OPERATOR_SUPPLIERS.put(Disjunction.TYPE, Disjunction::new); } public static Operator selectOperator(String typeStr) { Supplier<Operator> supplier = OPERATOR_SUPPLIERS.get(typeStr); if (supplier == null) { throw new IllegalArgumentException("Unknown operator type: " + typeStr); } return supplier.get(); } } // 循环初始化特定子类的例子:创建3个Disjunction实例 List<Operator> disjunctions = new ArrayList<>(); Supplier<Operator> disjSupplier = OperatorFactory.OPERATOR_SUPPLIERS.get(Disjunction.TYPE); for (int i = 0; i < 3; i++) { disjunctions.add(disjSupplier.get()); }
这个方案适合轻量场景,代码更简洁,新增子类只需要在静态块里加一行put即可,同样符合开闭原则。
方案3:反射(仅适合动态场景)
如果你的子类是动态加载的,或者标识是类的全限定名,可以用反射来实现,但要注意异常处理和性能开销(静态场景不推荐):
public Operator selectOperator(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException { Class<?> operatorClass = Class.forName(className); return (Operator) operatorClass.newInstance(); } // 循环初始化的话,直接循环调用就行 List<Operator> operators = new ArrayList<>(); for (int i = 0; i < 4; i++) { operators.add(selectOperator("com.yourpackage.Conjunction")); }
这个方案的优势是动态性强,但缺点也很明显:需要处理一堆异常,类型不安全,而且反射的性能比前两种方案差不少,所以只适合特殊的动态场景。
内容的提问来源于stack exchange,提问作者AntDm
相关产品推荐
相关产品推荐

