如何基于用户输入动态创建带不同参数的Shape子类实例?
解决方案:基于工厂+策略模式的动态Shape实例化方案
核心思路
采用工厂模式+策略模式的组合方案,为每个Shape子类配套实现一个专属的参数解析与实例创建器,核心逻辑仅依赖抽象创建器接口。新增子类时只需添加对应的创建器实现,无需修改现有核心代码,完美适配不同构造参数的场景。
1. 定义抽象创建器接口
先定义一个ShapeCreator接口,统一规范形状类型标识和实例创建逻辑:
public interface ShapeCreator { // 返回当前创建器支持的形状类型(如"Circle") String getShapeType(); // 解析分割后的输入参数数组,生成对应Shape实例 Shape create(String[] params); }
2. 为各Shape子类实现创建器
每个子类的创建器负责处理自身的参数解析与实例化,完全适配不同的构造参数数量:
Circle创建器示例
public class CircleCreator implements ShapeCreator { @Override public String getShapeType() { return "Circle"; } @Override public Shape create(String[] params) { // params[0]是类型标识,后续为实际参数:颜色、半径 String color = params[1]; double radius = Double.parseDouble(params[2]); return new Circle(color, radius); } }
Triangle创建器示例(假设构造参数为颜色+三条边长)
public class TriangleCreator implements ShapeCreator { @Override public String getShapeType() { return "Triangle"; } @Override public Shape create(String[] params) { String color = params[1]; double side1 = Double.parseDouble(params[2]); double side2 = Double.parseDouble(params[3]); double side3 = Double.parseDouble(params[4]); return new Triangle(color, side1, side2, side3); } }
3. 实现核心Shape工厂类
工厂类负责管理所有创建器,并对外提供统一的实例创建入口:
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ShapeFactory { private static final Map<String, ShapeCreator> CREATOR_REGISTRY = new HashMap<>(); // 初始化时注册所有创建器 static { // 手动注册示例,后续可通过反射自动扫描优化 CREATOR_REGISTRY.put(new CircleCreator().getShapeType(), new CircleCreator()); CREATOR_REGISTRY.put(new TriangleCreator().getShapeType(), new TriangleCreator()); } // 单实例创建方法 public static Shape createShape(String input) { String[] paramParts = input.split(",\\s*"); // 处理逗号+空格的分割场景 if (paramParts.length == 0) { throw new IllegalArgumentException("Invalid input format"); } String shapeType = paramParts[0]; ShapeCreator creator = CREATOR_REGISTRY.get(shapeType); if (creator == null) { throw new IllegalArgumentException("Unsupported shape type: " + shapeType); } return creator.create(paramParts); } // 批量创建并加入集合的工具方法 public static List<Shape> createAndCollectShapes(List<String> inputs) { List<Shape> shapeList = new ArrayList<>(); for (String input : inputs) { shapeList.add(createShape(input)); } return shapeList; } }
4. 反射自动扫描优化(可选)
如果不想手动注册每个创建器,可以通过反射扫描指定包下的所有ShapeCreator实现类,自动完成注册,进一步降低扩展成本:
import java.io.File; import java.net.URL; import java.util.Enumeration; // 替换ShapeFactory静态代码块中的手动注册为以下逻辑 static { try { String packageName = "com.yourpackage.shapes.creators"; // 你的创建器所在包 String path = packageName.replace('.', '/'); Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(path); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); File dir = new File(resource.getFile()); for (File file : dir.listFiles()) { if (file.getName().endsWith(".class")) { String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6); Class<?> creatorClass = Class.forName(className); if (ShapeCreator.class.isAssignableFrom(creatorClass) && !creatorClass.isInterface()) { ShapeCreator creator = (ShapeCreator) creatorClass.getDeclaredConstructor().newInstance(); CREATOR_REGISTRY.put(creator.getShapeType(), creator); } } } } } catch (Exception e) { e.printStackTrace(); } }
注:上述代码为原生Java实现的类扫描,也可以借助Spring的ClassPathScanningCandidateComponentProvider简化开发。
5. 使用示例
public class ShapeDemo { public static void main(String[] args) { String circleInput = "Circle, Blue, 7"; String triangleInput = "Triangle, Red, 3, 4, 5"; List<Shape> shapes = ShapeFactory.createAndCollectShapes(List.of(circleInput, triangleInput)); // 后续新增Square子类时,仅需编写SquareCreator并放入扫描包下,核心代码无需任何修改 } }
方案优势
- 完全符合开闭原则:新增Shape子类仅需添加对应创建器,无需改动现有核心逻辑。
- 参数适配灵活:每个创建器独立处理自身参数解析,完美适配不同数量、类型的构造参数。
- 扩展成本极低:结合反射扫描后,新增子类甚至无需修改工厂类的注册代码,真正实现无侵入扩展。
内容的提问来源于stack exchange,提问作者Masedko
相关产品推荐
相关产品推荐

