使用抽象工厂模式时,如何修改独立部署类的属性值?
这确实是工厂模式实践中很典型的矛盾场景——既要遵循依赖倒置原则依赖抽象的Shape接口,又需要对Rectangle这类具体形状的特有属性进行修改,同时还不能把专属方法塞进通用的Shape接口影响其他形状。下面给你几个实用的解决方案,你可以根据业务场景选择:
方案1:为特定形状定义专属接口
核心思路是拆分接口职责:通用的Shape接口保持纯净,只为所有形状共有的行为提供契约;而针对Rectangle这类有特有操作的形状,定义继承自Shape的专属接口,把它的特有方法放到这个专属接口里。这样既不污染通用接口,又能通过抽象接口而非具体类来操作属性。
修改后的代码示例:
首先新增专属接口RectangleShape:
public interface RectangleShape extends Shape { void setTopLeft(int top, int left); void setBottomRight(int bottom, int right); }
让Rectangle实现这个专属接口(原来的实现逻辑不变):
public class Rectangle implements RectangleShape { private int top, left, bottom, right; public Rectangle(int top, int left, int bottom, int right) { setTopLeft(top, left); setBottomRight(bottom, right); } @Override public void setTopLeft(int top, int left) { this.top = top; this.left = left; } @Override public void setBottomRight(int bottom, int right) { this.bottom = bottom; this.right = right; } }
然后在App中通过专属接口操作,避免依赖具体类:
public class App { ShapeFactory shapeFactory; public static void main(String[] args) { App app = new App(); app.setShapeFactory(new ShapeFactoryImpl()); Shape shape = app.create("rectangle"); // 现在依赖的是抽象接口RectangleShape,而非具体的Rectangle类 if (shape instanceof RectangleShape) { RectangleShape rectangle = (RectangleShape) shape; rectangle.setTopLeft(1,2); rectangle.setBottomRight(2,3); } } private void setShapeFactory(ShapeFactoryImpl shapeFactory) { this.shapeFactory = shapeFactory; } private Shape create(String shape) { return shapeFactory.create(shape); } }
这个方案的优势是职责清晰,后续如果需要新增Square这类也需要坐标操作的形状,只要让它实现RectangleShape接口即可,代码复用性高。
方案2:使用属性设置器模式(类似命令模式)
如果你的场景中需要统一处理不同形状的属性修改,可以定义一个通用的ShapePropertySetter接口,针对每种形状实现对应的属性设置逻辑。这样业务代码只需要依赖这个设置器接口和Shape,完全不需要接触具体的形状类。
代码示例:
首先定义通用的属性设置器接口:
import java.util.Map; public interface ShapePropertySetter { void setProperties(Shape shape, Map<String, Object> properties); }
然后为Rectangle实现专属的设置器:
import java.util.Map; public class RectanglePropertySetter implements ShapePropertySetter { @Override public void setProperties(Shape shape, Map<String, Object> properties) { if (shape instanceof Rectangle) { Rectangle rect = (Rectangle) shape; if (properties.containsKey("topLeft")) { int[] coords = (int[]) properties.get("topLeft"); rect.setTopLeft(coords[0], coords[1]); } if (properties.containsKey("bottomRight")) { int[] coords = (int[]) properties.get("bottomRight"); rect.setBottomRight(coords[0], coords[1]); } } } }
在App中通过设置器修改属性:
import java.util.HashMap; import java.util.Map; public class App { ShapeFactory shapeFactory; public static void main(String[] args) { App app = new App(); app.setShapeFactory(new ShapeFactoryImpl()); Shape rectangle = app.create("rectangle"); // 使用设置器修改属性,无需依赖具体类 ShapePropertySetter rectSetter = new RectanglePropertySetter(); Map<String, Object> props = new HashMap<>(); props.put("topLeft", new int[]{1,2}); props.put("bottomRight", new int[]{2,3}); rectSetter.setProperties(rectangle, props); } private void setShapeFactory(ShapeFactoryImpl shapeFactory) { this.shapeFactory = shapeFactory; } private Shape create(String shape) { return shapeFactory.create(shape); } }
这个方案适合需要批量设置属性、或者有统一属性配置逻辑的场景,后续新增其他形状时,只需要新增对应的ShapePropertySetter实现即可。
方案3:在工厂创建阶段直接传入属性
如果你的属性是在创建形状时就能确定的,那最直接的方式就是修改工厂的创建方法,让它支持传入属性参数,这样就完全避免了创建后修改属性的需求,从根源上解决依赖问题。
代码示例:
修改ShapeFactory接口,支持传入属性参数:
import java.util.Map; public interface ShapeFactory { Shape create(String shape, Map<String, Object> properties); }
修改工厂实现类,根据参数创建对应形状:
import java.util.Map; public class ShapeFactoryImpl implements ShapeFactory { @Override public Shape create(String shape, Map<String, Object> properties) throws RuntimeException { if (shape.equals("rectangle")) { // 从参数中获取属性,没有则使用默认值 int top = (int) properties.getOrDefault("top", 0); int left = (int) properties.getOrDefault("left", 0); int bottom = (int) properties.getOrDefault("bottom", 1); int right = (int) properties.getOrDefault("right", 1); return new Rectangle(top, left, bottom, right); } throw new IllegalArgumentException("Unsupported shape: " + shape); } }
在App中直接创建带属性的形状:
import java.util.HashMap; import java.util.Map; public class App { ShapeFactory shapeFactory; public static void main(String[] args) { App app = new App(); app.setShapeFactory(new ShapeFactoryImpl()); // 创建时直接传入属性,无需后续修改 Map<String, Object> props = new HashMap<>(); props.put("top", 1); props.put("left", 2); props.put("bottom", 2); props.put("right", 3); Shape rectangle = app.create("rectangle", props); } private void setShapeFactory(ShapeFactoryImpl shapeFactory) { this.shapeFactory = shapeFactory; } private Shape create(String shape, Map<String, Object> properties) { return shapeFactory.create(shape, properties); } }
这个方案是最简洁的,适合属性在创建时就能确定的场景,完全遵循了工厂模式的初衷——把对象的创建和使用分离。
内容的提问来源于stack exchange,提问作者Thomas Lehner

