工厂设计模式和违反OCP(开放式原则)

问题描述 投票:3回答:2

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,而且并不复杂。有什么原因找不到我提及的工厂设计模式教程吗?

java factory open-closed-principle
2个回答
2
投票

此方法有一些缺点。

首先,当传递给getShape的Class需要构造函数参数时,.newInstance将失败。例如:

public class Circle {
   public Circle(int diameter) {
      //something
   }
}

您可以通过使用getConstructor并找出要传递的参数来进行反思,但这很复杂且容易出错。并且您在编译时失去类型安全性。工厂类将如何知道要传递给直径的值?

工厂设计模式的优点之一是,调用者不必知道调用时使用了哪种实现类。请看以下示例:

public class ShapeFactory {
   public Shape getCircle(int diameter){
      return new Circle(int diameter);
   }
}

无论何时调用此方法,调用者都不必依赖Circle类:

Shape s = ShapeFactory().getCircle(10);
s.draw();

以这种方式,只有ShapeFactory取决于Circle。因此,当您更改或替换Circle类时,只需更改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依赖注入框架,但是它们都可以像这样工作。

这些框架所做的与您所提议的完全相同(诸如newInstancegetConstructor之类的东西,但更多的东西,它们只是隐藏了所有反射的复杂性。


0
投票

[我认为@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);
    }
  }    
}

如果原始的虚构的“形状”库的设计人员希望通过形状类型轻松创建新形状,则可以实现注册表:

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 injectionGuice作为一个很好的例子。

© www.soinside.com 2019 - 2024. All rights reserved.