Does the Factory Method pattern (not to be confused with the Factory or Abstract Factory patterns) violate the Open/Closed principle?
Update: To clarify, I'm referring to the scenario where a concrete class has static factory methods on it. For example (this is from the Wikipedia page on FMP):
class Complex
{
public static Complex fromCartesian(double real, double imag) {
return new Complex(real, imag);
}
public static Complex fromPolar(double modulus, double angle) {
return new Complex(modulus * cos(angle), modulus * sin(angle));
}
private Complex(double a, double b) {
//...
}
}
Doesn't the private constructor prevent the class from being subclassed, i.e. extended?
Wouldn't the class have to be modified to support new factory methods? For example, if the class initially only had fromCartesian and later fromPolar was needed, didn't the class have to be modified to support this?
Don't both of these violate Open/Closed?
No, it doesn't violate the Open/Closed principle at all.
Open/Closed means you can modify the way a system works without modifying the code that already exists. You can extend the code and use it in different ways, but the old code is still in tact and doesn't need to be re-tested.
The Factory Method pattern will create a different type of object based on specified parameters. Factory Method actually works well with the Open/Closed principle if done correctly. However, if you create a new class and then want the Factory Method to create a new object of that type you would have to change the Factory Method.
Although, if you had some kind of configuration file or something of that sort that is read in by the Factory Method then you wouldn't have to change the Factory Method ... just the config file that then dictates what object will be created by the Factory Method.
The Factory pattern isn't inherently a violator of OCP.
It depends on how you take the behavior of Complex
further.
If Complex
is required to support the production of new types of Complex
object, and you choose to modify Complex
by adding new fromX
methods are added to support them, then this means that Complex
becomes a violator of the OCP because Complex
must be re-opened for modification:
class Complex
{
public static Complex fromCartesian(double real, double imag) {
return new Complex(real, imag);
}
public static Complex fromPolar(double modulus, double angle) {
return new Complex(modulus * cos(angle), modulus * sin(angle));
}
//class opened for modification
public static Complex fromOtherMeans(String x , String y) {
return new Complex(x, y);
}
}
You could push this problem down into a text file or properties file of some sort in order to absolve yourself of having to change the java class, but it doesn't prevent you from having to write extra logic in this area of the solution in order to support new types of Complex
.
Depending on the usage of Complex
in your design (how are the various types different? How are you using them?), there are some alternative options which may apply well.
One such OCP friendly alternative is to subclass Complex
to provide the additional factory methods. A subclass is the simplest illustration of how Complex
is extended but not modified.
Another OCP friendly alternative to altering Complex
in this case is the Decorator pattern. Continuously decorating Complex
with the ability to create new variants of Complex
respects the OCP because Complex
is not modified but is extended by wrapping it with new functionality.
A third alternative might be to alter the structure of Complex
so that its calculation is supplied by composition. This would open up to you the opportunity to use the Strategy pattern to diferentiate between the different behaviours of Complex
.
The thing about the Factory pattern is that it helps context code respect OCP. One might employ one of the techniques above in order to stay on the right side of the OCP with their Factory class, but your colleagues are likely to take one look at the object graph, question the wisdom of having an object graph over a single Factory, and simplify it back into one Factory, which brings you back to to the first example.
In such cases, rather than trying to bend your implementation of the Factory pattern to respect the SOLID principles, consider why you're using it at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With