There are a few drawbacks to this method.
Firstly, when the Class passed to getShape requires a constructor argument, the .newInstance will fail. For example:
public class Circle {
public Circle(int diameter) {
//something
}
}
You could get into reflection by using getConstructor
and figuring out what arguments to pass, but that is complex and error prone. And you lose type safety at compilation time. And how would the factory class know what values to pass to diameter?
One of the advantages of the factory design pattern is that the caller doesn't have to know what implementing class is used when calling. Take the following example:
public class ShapeFactory {
public Shape getCircle(int diameter){
return new Circle(int diameter);
}
}
Whenever you call this method, the caller doesn't have need a dependency on the Circle class:
Shape s = ShapeFactory().getCircle(10);
s.draw();
In this way, only the ShapeFactory
depends on the Circle
. So when you change or replace the Circle class, only the ShapeFactory
has to change.
To create make the shape program OCP compliant, we could replace the ShapeFactory with a dependency injection framework. The below code is pseudo-code that shows how this could work
// 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)
There are many Java Dependency Injection frameworks but they all work something like this.
These frameworks do the exact same thing what you propose (things like newInstance
and getConstructor
, but a lot more of those), they just hide all the reflection complexity.
.getConstructor
method before.newInstance
and pass the parameters tonewInstance
. – Permeate