Simple Factory vs Factory Method: Switch statement in factory vs. client
Asked Answered
B

1

6

I understand that one of the main advantages of the Factory Method over Simple Factory is that it doesn't violate the Open-Closed SOLID Principle. That is, the former doesn't require modifying the switch statement when new types are added.

There is one piece on which I am hoping to get clarification. If I were to use a simple factory, I would have a factory like this (simplified):

public class ObjectFactory {
    public static IObject CreateObject(ObjectTypeEnum objectType) {
        switch (objectType) {
            case TypeA:
                return ObjectA;
                break;
            case TypeB:
                return ObjectB;
                break;
            case TypeC:
                return ObjectC;
                break;
        }
    }
}

and the client would call it like this:

IObject myObject = ObjectFactory.CreateObject(objectType);

The disadvantage in the literature is that CreateObject will need to be modified when new object types are added.

But with the Factory Method, wouldn't we just be moving this modification from the factory to the client, like this (client code):

IObject myObject;
switch (objectType) {
            case TypeA:
                myObject = ObjectAFactory.CreateObject();
                break;
            case TypeB:
                myObject = ObjectBFactory.CreateObject();
                break;
            case TypeC:
                myObject = ObjectCFactory.CreateObject();
                break;
}

In this case the client will need to be modified each time a new type is added, versus in the previous case the factory would need to be modified. So what is the advantage then of one over the other? Please don't mark this as duplicate, I have looked at many SO posts about factories and none address this specific distinction.

Is there a better solution that doesn't violate the Open/Closed Principle on either the client or factory side?

Bloem answered 17/2, 2015 at 17:52 Comment(2)
Related: Differences between Abstract Factory Pattern and Factory MethodCrwth
I met the same problem as well. Looks like factory method pattern still violate the open-closed principle if still use the switch statement. In other words, we still need to modify the code.Woman
L
1

The standard Abstract Factory design pattern doesn't help?
Simplified Java code:

public interface IFactory {
    IObject createObject();
}

public class FactoryA implements IFactory {
    public IObject createObject() {
        return new ObjectA();
    }
}

public class FactoryB implements IFactory {
    public IObject createObject() {
        return new ObjectB();
    }
}

Client is configured (injected) with the needed Factory at run-time
    IFactory myFactory = ...   // new FactoryA();
...
IObject  myObject = myFactory.createObject();
...

See also the GoF Design Patterns Memory / Abstract Factory at http://w3sdesign.com.

VARIANT 2
Instead of using enum object types, define your object types with polymorphism (to avoid switch statements). Simplified Java code:

public interface IObjectType {
    int getObjectType();
    IObject createObject();
}

public class ObjectTypeA implements IObjectType {
    ...
    public IObject createObject() {
        return new ObjectA();
    }
}

public class ObjectTypeB implements IObjectType {
    ...
    public IObject createObject() {
        return new ObjectB();
    }
}

Client determines object type 
IObjectType myObjectType = ...   // new ObjectTypeA();
...
IObject  myObject = myObjectType.createObject();
...

My conclusion:
I think, a better solution would be to design your types with polymorphism instead of using enum constans. This would avoid switch statements and wouldn't violate the Open/Closed Principle on either the client or factory side.

Lorileelorilyn answered 18/2, 2015 at 11:47 Comment(7)
This is essentially a variation of my second option above. The reason this doesn't work for me is that in my case the factory's "client" is actually a Web API. The Web API's client ("client's client") will be the determining factor for what the object type is, so I don't see a way to inject it without doing a switch on the object type, whether that's in the api that creates the IFactory or in the factory itself.Bloem
How do clients determine the object type?Lorileelorilyn
The client passes up the object type they want to the api. The object type is an enum value.Bloem
I mean, for example, is object type TypeA = InterfaceA / ClassA / typeOf ObjectA or the like.Lorileelorilyn
objectType is an enum value.Bloem
(1) OK, putting everything into the same answer. (2) In my conclusion, I answered your question: Is there a better solution that doesn't violate the Open/Closed Principle on either the client or factory side? You say that you can't change the design - so why do you ask the question anyway?Lorileelorilyn
I didn't say that no aspect of the design could be changed. I said the api's client has no knowledge of entire types of the api. Forcing the client to know about the api's internal types and to pass up an entire type is not a good design.Bloem

© 2022 - 2024 — McMap. All rights reserved.