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?

mayabelle
  • 9,804
  • 9
  • 36
  • 59
  • Related: [Differences between Abstract Factory Pattern and Factory Method](https://stackoverflow.com/a/50786084/1371329) – jaco0646 Jan 14 '19 at 19:26
  • 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. – Ben Jun 26 '21 at 23:30

1 Answers1

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.

GFranke
  • 237
  • 3
  • 8
  • 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. – mayabelle Feb 18 '15 at 15:17
  • How do clients determine the object type? – GFranke Feb 18 '15 at 21:42
  • The client passes up the object type they want to the api. The object type is an enum value. – mayabelle Feb 18 '15 at 21:43
  • I mean, for example, is object type TypeA = InterfaceA / ClassA / typeOf ObjectA or the like. – GFranke Feb 18 '15 at 22:32
  • objectType is an enum value. – mayabelle Feb 18 '15 at 22:41
  • (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? – GFranke Feb 23 '15 at 17:38
  • 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. – mayabelle Feb 23 '15 at 18:52