工厂设计模式与违反OCP(Open-Closed Principle)
Factory design pattern and violation of OCP (Open-Closed Principle)
this tutorial中的工厂明显违反了OCP。每次系统添加一个形状,我们都需要在工厂中添加它来支持它。
我正在考虑另一种实现,我想知道是否有任何缺点。
public class ShapeFactory {
//use getShape method to get object of type shape
public Shape getShape(Class<? extends Shape> shapeType){
return shapeType.newInstance();
}
}
这个实现看起来不违反 OCP,也不复杂。有什么原因我找不到任何提到它的工厂设计模式教程吗?
这种方法有一些缺点。
首先,当传递给 getShape 的 Class 需要构造函数参数时,.newInstance 将失败。例如:
public class Circle {
public Circle(int diameter) {
//something
}
}
您可以通过使用 getConstructor
并找出要传递的参数来进行反思,但这很复杂且容易出错。而且你在编译时失去了类型安全。工厂 class 如何知道要传递给直径的值?
工厂设计模式的优点之一是调用者在调用时不必知道使用什么实现class。举个例子:
public class ShapeFactory {
public Shape getCircle(int diameter){
return new Circle(int diameter);
}
}
无论何时调用此方法,调用者都不需要依赖于 Circle class:
Shape s = ShapeFactory().getCircle(10);
s.draw();
这样,只有ShapeFactory
依赖于Circle
。因此,当您更改或替换 Circle class 时,只需更改 ShapeFactory
。
为了使形状程序符合 OCP 标准,我们可以用依赖注入框架替换 ShapeFactory。下面的代码是伪代码,展示了它是如何工作的
// define the classes
class Circle {}
class Square {}
// for every class, provide a factory method. These do not have to exist inside a factory class.
public Circle createCircle() {
return new Circle(10)
}
public Circle createSquare() {
return new Square(42, 5)
}
public class Painter {
//when a class requires an instance of the Circle class, the dependency injection framework will find `createCircle`, call it and add the result as an argument here.
public Painter(Circle circle) {
circle.draw();
}
}
//when you need a painter object, we don't create it yourself but let the dependency framework do the heavy lifting
Painter p = dependencyframework.getInstanceOf(Painter.class)
有很多 Java 依赖注入框架,但它们都是这样工作的。
这些框架与您提出的建议完全相同(例如 newInstance
和 getConstructor
,但还有很多),它们只是隐藏了所有反射复杂性。
我认为@hfontanez 对问题 "Does the Factory Pattern violate the Open/Closed Principle?" 的回答涵盖了。如果您要添加新的 Shape 子类,您还必须以某种方式添加一种方法来创建它们的实例。假设您不能修改原始 ShapeFactory,因为它是第三方库的一部分,但您可以子类化或修饰原始工厂以添加对新形状的支持。扩展示例将如下所示:
public class AdvancedShapeFactory {
private final ShapeFactory factory = new ShapeFactory();
public Shape getShape(String shapeType) {
if (shapeType.equalsIgnoreCase("PENTAGON")) {
return new Pentagon();
} else {
return factory.getShape(shapeType);
}
}
}
如果最初虚构的 "Shapes" 库的设计者想要按形状类型轻松创建新形状,他们可以实现一个注册表:
public class ShapeRegistry {
private static final Map<String, Class<Shape>> shapeTypes = new HashMap<>();
public void registerShape(String shapeType, Class<Shape> shapeClass) {
shapeTypes.put(shapeType, shapeClass);
}
public Shape getShape(String shapeType) throws InstantiationException, IllegalAccessException {
if (shapeTypes.containsKey(shapeType)) {
return shapeTypes.get(shapeType).newInstance();
}
return null;
}
}
值得一读 dependency injection and Guice 作为一个很好的例子。
this tutorial中的工厂明显违反了OCP。每次系统添加一个形状,我们都需要在工厂中添加它来支持它。 我正在考虑另一种实现,我想知道是否有任何缺点。
public class ShapeFactory {
//use getShape method to get object of type shape
public Shape getShape(Class<? extends Shape> shapeType){
return shapeType.newInstance();
}
}
这个实现看起来不违反 OCP,也不复杂。有什么原因我找不到任何提到它的工厂设计模式教程吗?
这种方法有一些缺点。
首先,当传递给 getShape 的 Class 需要构造函数参数时,.newInstance 将失败。例如:
public class Circle {
public Circle(int diameter) {
//something
}
}
您可以通过使用 getConstructor
并找出要传递的参数来进行反思,但这很复杂且容易出错。而且你在编译时失去了类型安全。工厂 class 如何知道要传递给直径的值?
工厂设计模式的优点之一是调用者在调用时不必知道使用什么实现class。举个例子:
public class ShapeFactory {
public Shape getCircle(int diameter){
return new Circle(int diameter);
}
}
无论何时调用此方法,调用者都不需要依赖于 Circle class:
Shape s = ShapeFactory().getCircle(10);
s.draw();
这样,只有ShapeFactory
依赖于Circle
。因此,当您更改或替换 Circle class 时,只需更改 ShapeFactory
。
为了使形状程序符合 OCP 标准,我们可以用依赖注入框架替换 ShapeFactory。下面的代码是伪代码,展示了它是如何工作的
// define the classes
class Circle {}
class Square {}
// for every class, provide a factory method. These do not have to exist inside a factory class.
public Circle createCircle() {
return new Circle(10)
}
public Circle createSquare() {
return new Square(42, 5)
}
public class Painter {
//when a class requires an instance of the Circle class, the dependency injection framework will find `createCircle`, call it and add the result as an argument here.
public Painter(Circle circle) {
circle.draw();
}
}
//when you need a painter object, we don't create it yourself but let the dependency framework do the heavy lifting
Painter p = dependencyframework.getInstanceOf(Painter.class)
有很多 Java 依赖注入框架,但它们都是这样工作的。
这些框架与您提出的建议完全相同(例如 newInstance
和 getConstructor
,但还有很多),它们只是隐藏了所有反射复杂性。
我认为@hfontanez 对问题 "Does the Factory Pattern violate the Open/Closed Principle?" 的回答涵盖了。如果您要添加新的 Shape 子类,您还必须以某种方式添加一种方法来创建它们的实例。假设您不能修改原始 ShapeFactory,因为它是第三方库的一部分,但您可以子类化或修饰原始工厂以添加对新形状的支持。扩展示例将如下所示:
public class AdvancedShapeFactory {
private final ShapeFactory factory = new ShapeFactory();
public Shape getShape(String shapeType) {
if (shapeType.equalsIgnoreCase("PENTAGON")) {
return new Pentagon();
} else {
return factory.getShape(shapeType);
}
}
}
如果最初虚构的 "Shapes" 库的设计者想要按形状类型轻松创建新形状,他们可以实现一个注册表:
public class ShapeRegistry {
private static final Map<String, Class<Shape>> shapeTypes = new HashMap<>();
public void registerShape(String shapeType, Class<Shape> shapeClass) {
shapeTypes.put(shapeType, shapeClass);
}
public Shape getShape(String shapeType) throws InstantiationException, IllegalAccessException {
if (shapeTypes.containsKey(shapeType)) {
return shapeTypes.get(shapeType).newInstance();
}
return null;
}
}
值得一读 dependency injection and Guice 作为一个很好的例子。