Java中基于布尔值选择子类创建实例的最佳实现与工厂模式问题
首先明确一个核心原则:不要为了解耦而强行做无意义的抽象。如果当前场景下BaseObject只有GoodObject、BadObject两个固定子类,创建逻辑仅为简单构造传参,没有全局统一管控实例创建、后续频繁扩展子类的需求,你原本写的三元表达式本身就是最优实现——硬套设计模式抽工厂只会增加不必要的代码复杂度,没有实际收益。
如果确实存在解耦需求(比如后续要新增子类、需要统一埋点/参数校验/实例缓存逻辑、构造参数复杂需要统一组装),以下是比你当前实现更合理的方案:
方案1:无状态简单工厂(适配绝大多数常规场景)
你当前写的Builder+工厂实现有两个明显缺陷:
- 工厂类内部维护了所有属性的可变状态,多线程并发调用时会出现属性串扰,直接导致创建出错误的对象
- 要求调用方提前调用
withGoodProperties/withBadProperties传参,本质还是把对象类型的判断逻辑暴露给了业务层,没有实现解耦,反而比直接new多了冗余调用
正确的简单工厂应该是无状态、线程安全的,差异化属性通过参数封装传递,不要在工厂内部存临时状态:
// 1. 封装构造参数:公共属性放基类参数,子类差异化属性放对应参数子类 public class BaseCreateParam { // 所有BaseObject子类共有的属性 } public class GoodCreateParam extends BaseCreateParam { // GoodObject独有的属性 } public class BadCreateParam extends BaseCreateParam { // BadObject独有的属性 } // 2. 无状态工厂实现 public class ObjectFactory { // 用Map注册类型和对应的创建逻辑,后续新增子类只需要加映射,不用修改核心创建逻辑 private static final Map<Class<?>, Function<BaseCreateParam, BaseObject>> CREATOR_MAPPER = Map.of( GoodObject.class, param -> new GoodObject((GoodCreateParam) param), BadObject.class, param -> new BadObject((BadCreateParam) param) ); // 泛型方法,支持直接按类型创建 @SuppressWarnings("unchecked") public static <T extends BaseObject> T create(Class<T> targetType, BaseCreateParam param) { Function<BaseCreateParam, BaseObject> creator = CREATOR_MAPPER.get(targetType); if (creator == null) { throw new IllegalArgumentException("不支持的对象类型:" + targetType.getName()); } return (T) creator.apply(param); } // 兼容原有传isGood判断的调用方式 public static BaseObject create(boolean isGood, BaseCreateParam param) { return create(isGood ? GoodObject.class : BadObject.class, param); } }
业务层调用非常简洁,完全感知不到具体子类的存在:
public BaseObject businessLogic(boolean isGood, GoodCreateParam goodParam, BadCreateParam badParam){ // 前置业务逻辑 BaseCreateParam useParam = isGood ? goodParam : badParam; return ObjectFactory.create(isGood, useParam); }
这个实现的优势是没有额外的学习成本,线程安全,后续扩展子类不需要修改工厂核心逻辑,符合开闭原则。
方案2:工厂方法模式(适配子类创建逻辑复杂的场景)
如果不同子类的初始化逻辑差异极大(比如需要依赖外部组件、做复杂参数校验、初始化关联资源、做实例池缓存),不要把所有创建逻辑堆在同一个工厂类里,给每个子类实现独立的工厂,再通过统一注册表对外提供服务:
// 统一工厂接口 public interface BaseObjectFactory<T extends BaseObject> { T create(BaseCreateParam param); } // GoodObject专属工厂,独立维护GoodObject的复杂创建逻辑 public class GoodObjectFactory implements BaseObjectFactory<GoodObject> { // 可以在这里注入需要的外部依赖 @Override public GoodObject create(BaseCreateParam param) { GoodCreateParam goodParam = (GoodCreateParam) param; // 复杂参数校验、资源初始化、依赖调用逻辑 return new GoodObject(goodParam); } } // BadObject专属工厂实现逻辑同上 public class BadObjectFactory implements BaseObjectFactory<BadObject> { @Override public BadObject create(BaseCreateParam param) { BadCreateParam badParam = (BadCreateParam) param; return new BadObject(badParam); } }
外层只需要维护一个工厂注册表,根据类型路由到对应的子工厂即可,业务层依然不需要感知具体子类和子工厂的存在。
关于Builder模式的正确用法
如果子类构造参数多、需要链式组装参数,不要把Builder逻辑放在工厂类里,应该把Builder和具体子类绑定:
- 公共属性的组装逻辑放在抽象基类Builder里
- 每个子类实现自己的Builder,维护自己的差异化属性组装逻辑
- 工厂层只负责根据条件返回对应的Builder实例,不存储任何参数状态
这种实现既保留了链式传参的便利性,也不会破坏工厂的无状态特性,不会出现并发安全问题。
最后再强调一次:设计模式是解决问题的工具,不是必须遵守的规范。当抽象带来的可维护性、扩展性收益覆盖不了抽象本身的复杂度时,直接写简单的判断逻辑永远是最优选择。
内容的提问来源于stack exchange,提问作者waynewingorc

