基于普通父类的Factory Method实现是否合规?代码有无问题?
关于你的Factory Method模式实现的分析与建议
首先直接回应你的两个核心问题:
一、这是不是Factory Method模式?
你的实现不属于标准的Factory Method(工厂方法)模式,它更接近Simple Factory(简单工厂)模式。
为什么这么区分?标准Factory Method的核心是「将对象的创建延迟到子类」:它需要定义一个抽象工厂(接口或抽象类),里面声明一个创建对象的抽象方法,然后由具体的工厂子类去实现这个方法,每个子类对应创建一种产品实例。
而你的MyClassFactory是一个静态类,用一个静态方法集中处理所有产品的创建逻辑——这正是Simple Factory的典型特征:把对象创建的逻辑封装在单一的工厂类里,虽然简化了实现,但没有利用子类扩展创建逻辑的特性。
不过要说明:Simple Factory是Factory Method的简化变体,在业务场景简单、产品子类不会频繁新增的情况下,这种实现完全够用,没必要强行套标准模式,适合自己的需求才是最重要的。
二、代码存在的问题?
你的代码能正常运行,但有几个可以优化的点,避免后续维护踩坑:
- 父类A的定位模糊:你说部分场景会直接实例化A,但如果A是作为产品的基类,后续还会新增更多子类,直接实例化A可能会导致业务逻辑混乱——比如后续调用子类特有的
getX3()方法时,如果拿到的是A的实例,就会报错。如果A不应该被直接实例化,建议改成抽象类;如果确实需要实例化A,要明确它的业务定位(比如作为基础通用实例)。 - 工厂的判断逻辑违反开闭原则:现在用
switch硬编码判断criteria,后续新增子类(比如D、E)时,必须修改MyClassFactory的代码,这不符合「对扩展开放、对修改关闭」的设计原则。 - 命名不规范:父类A里的
x1()是getter,但其他getter都是getXxx格式,这种不一致会导致调用混乱,建议统一成JavaBean标准的getX1();另外getMyClass方法名可以更清晰,比如createInstance;criteria的字符串取值("class B")容易出现拼写错误,建议改成枚举。 - 异常处理缺失:工厂方法里如果
criteria传入错误值,直接返回A的实例,但没有任何提示,后续排查问题会比较麻烦。
三、代码优化示例
1. 统一产品类的命名(可选把A改成抽象类)
// 如果不需要直接实例化A,改成抽象类 public abstract class A { private String x1 = "some value"; private String x2; // 统一getter命名为JavaBean标准格式 public String getX1() { return x1; } public void setX1(String x1) { this.x1 = x1; } public String getX2() { return x2; } public void setX2(String x2) { this.x2 = x2; } } public class B extends A { private String x3; private String x4; public String getX3() { return x3; } public void setX3(String x3) { this.x3 = x3; } public String getX4() { return x4; } public void setX4(String x4) { this.x4 = x4; } } public class C extends A { private String x5; private String x6; public String getX5() { return x5; } public void setX5(String x5) { this.x5 = x5; } public String getX6() { return x6; } public void setX6(String x6) { this.x6 = x6; } }
2. 优化工厂类(符合开闭原则)
用枚举统一产品类型,再用Map存储类型与类的映射,新增子类时只需添加映射,不用修改工厂类的核心逻辑:
// 用枚举定义产品类型,避免字符串硬编码错误 public enum ProductType { CLASS_A, CLASS_B, CLASS_C } public class MyClassFactory { // 存储类型与对应产品类的映射 private static final Map<ProductType, Class<? extends A>> PRODUCT_MAP = new HashMap<>(); // 静态块初始化映射 static { PRODUCT_MAP.put(ProductType.CLASS_A, A.class); PRODUCT_MAP.put(ProductType.CLASS_B, B.class); PRODUCT_MAP.put(ProductType.CLASS_C, C.class); } public static A createInstance(ProductType type) { Class<? extends A> clazz = PRODUCT_MAP.get(type); if (clazz == null) { // 这里可以抛出自定义异常,或者返回默认实例 throw new IllegalArgumentException("Invalid product type: " + type); } try { return clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { // 处理实例化异常,比如抛出自定义异常 throw new RuntimeException("Failed to create product instance", e); } } }
3. 如果要实现标准的Factory Method模式
如果你的业务场景需要频繁新增子类,且希望严格遵循开闭原则,可以改成标准的Factory Method:
// 抽象工厂类 public abstract class AbstractProductFactory { public abstract A createProduct(); } // 具体工厂:创建B实例 public class BProductFactory extends AbstractProductFactory { @Override public A createProduct() { return new B(); } } // 具体工厂:创建C实例 public class CProductFactory extends AbstractProductFactory { @Override public A createProduct() { return new C(); } } // 使用示例 AbstractProductFactory factory = new BProductFactory(); A product = factory.createProduct();
这种方式的好处是新增产品时只需要新增对应的工厂子类,不需要修改现有代码,但会增加类的数量,适合复杂的业务场景。
内容的提问来源于stack exchange,提问作者Genadio
相关产品推荐
相关产品推荐

