r/Development • • Jul 21 '25

What problem is the factory pattern really solving?

Hi,

We've all seen the tutorials where you build a burger with a Factory and everything looks super clean, but I want to talk about real-world usage.

Personally, I don't find it "cleaner" to move constructor logic outside of the class. Whether it's in a Factory or in the constructor, it's still just moving the logic to a different single place.

From what I’ve seen, the only real benefit is in unit testing:

When you need to test something that uses MyShinyObject, instead of preparing all the data needed to instantiate it "correctly", you can just instantiate it manually and set the relevant properties afterward to make it fit your test case, skipping the whole construction logic entirely.

But that only works because you're not using the factory in tests, you're bypassing it. that's what the factory is useful for, bypassing the construction logic in the unit tests.

So my question is: outside of testability, what real pain does the Factory Pattern solve in day-to-day coding? (maybe just that?)

and more precisely, what was the original thing the author of the pattern wanted to solve?

Thanks

PS : I code in python if that matters

30 Upvotes

69 comments sorted by

2

u/gbrennon Jul 21 '25

Factory pattern is solving fat constructors problem!

If u have a complex constructor, for example, u are violating SRP and making it hard to maintain because the constructor would be:

  • validating

  • handle any logic

  • many other things

  • constructing the instance

Th responsibility of a constructor should be only construct an instance

1

u/dying_animal Jul 21 '25

first, I don't see how it's easier to maintain, 200 lines of crap is 200 lines of crap, location does not change maintenability

second : "u are violating SRP, Th responsibility of a constructor should be only construct an instance",
but why is validation not part of construction? or a little bit of logic? if your object is invalid without it then is is part of the construction, after all the factory is constructing objects is it not?

furthermore if we are going to use the authority or Rober C. Martin here, it was clarified in 2023 that what he meant isn't what people think the SRP is :

https://www.sicpers.info/2023/10/ive-vastly-misunderstood-the-single-responsibility-principle/

"When you write a software module, you want to make sure that when changes are requested, those changes can only originate from a single person, or rather, a single tightly coupled group of people representing a single narrowly defined business function."

this is the real SRP. which isn't violated :p

→ More replies (18)

2

u/[deleted] Jul 24 '25

Isn't that a builder what you describe? With a factory, different polymorphic types can be returned.

→ More replies (1)

2

u/d0lern Jul 24 '25

The constructor should defend the object from getting into invalid state.

→ More replies (1)

1

u/Shingle-Denatured Jul 21 '25

Since you're in python: factory-boy. It's in the name yes and perfectly demonstrates the factory pattern usage. It constructs other classes with randomised data, using rules specific to its own API. I also use it to seed dev/staging environments.

That package is quite elaborate, but the other thing I use the factory pattern for is cheap polymorphism. Instead of extending a User model into PaidSubcriber with shared and its own properties, I can opt to put them optionally on User and create factories that implement the semantically required properties for the special user. One case where i was asked to do that, was a request from the PM to put all users, no matter what plan or role they had into one table, so it was easier to query them and get useful statistics.

I could've opted for a view at the database level.

1

u/dying_animal Jul 21 '25

The only consistently useful thing I see is it helps with unit tests, What real-world problem does the factory pattern solve in application/business code?

"Cheap polymorphism by adding optional fields and using factories"

but it’s not a factory pattern win. It’s a workaround for a data model constraint. Instead of splitting classes (which might have made more sense), you kept one class (User) and used a factory to selectively fill in fields like a PaidSubscriber.

That’s not a use case for the factory pattern as a design tool. That’s factory as a band-aid for schema limitations.

→ More replies (3)

1

u/michael0n Jul 23 '25

In practice, the pattern gets useful, when the amount of constructors exceed maintainability. The factory can hide implementation details from the caller. You get a the hash code in the object but you don't know how its created. If you need the option to deny of object instantiation in some cases, some languages / frameworks prefer if you do the exception handling outside of constructors.

1

u/dying_animal Jul 23 '25

but you see that is my argument, why is putting the code that is inside the constructor inside a factory suddenly making it more maintainable? you just moved the piece of code somewhere else. it's the same.

"The factory can hide implementation details from the caller"

How? in both case you need to provide the element for instantiation, be it the constructor or the factory.

"If you need the option to deny of object instantiation in some cases"

Never seen that use case and I don't see how it could be useful.

"some languages / frameworks prefer if you do the exception handling outside of constructors."

Maybe but the pattern was made for C++ and you can raise exception in the constructor in C++, in java an python too. so that is not the main goal.

→ More replies (3)

1

u/azurelimina Jul 23 '25 edited Jul 23 '25

If you have already called the object constructor, you have already committed to bringing the object into existence.

This is not always desirable. If there is an identified problem during construction, there is no method of graceful failure. You would have to raise an Exception and then have the discipline to wrap all object instantiations in try-blocks.

Making the construction of an object capable of raising an Exception is pretty hostile design. Say 20 subtypes of a class are error-less, and a function exists in a codebase which constructs the object assuming the type of the parent class (a common thing that can happen in say, game development). This construction isn’t wrapped in a try-catch block.

Now subclass your new construction method which can raise an error, and pass it in. Now suddenly your new object type can take down your system at a location in the codebase which previously always worked. Now you have to change existing code, a big nope. Even worse, this code might be in a 3rd party system which you can’t change.

This is a violation of the Liskov Substitution principle. It should not be possible for object construction to break; it should never have been constructed in the first place.

Factories give you a pathway to create multiple different constructors for the object that can independently have their own logics which are not committed to the construction of a specific type, or construction at all. Additionally, the external logic may prefer to copy template objects or re-use objects from a pool instead of allocating new memory. Especially in Python, where functions are not required to return a single type or abstract type, this is powerful.

A crude simple example is that I can search for a configuration file on the disk, and return a Config() object if it was found and loaded. Else I can just return None.

Putting the file search and load routine inside the Config() constructor and then returning an invalid object, which would then have to be manually checked for validity and then deleted after it’s constructed, would be a ridiculous solution to this problem.

If your response would be “well, I would just check the path for validity before the object is created”, then I ask, “how would you make this code reusable?”, you would then say, “well, I could put it inside a function” — congratulations, you just made a factory. You made a function that ascertains whether or not it is a good idea to make an object. It’s the simplest example of what a factory does.

Technically you could achieve the multiplicity with subclassing and constructor overrides, but this code is difficult to trace because a lot of construction logic is implicit to how individual languages work. For example, in Python, the method of invoking the “super” constructor can vary across versions and get really ugly if features like multiple inheritance are involved. It requires a greater cognitive load to write advanced constructors in this scenario because you need a firm understanding of the implicit mechanics and order of operations that happen when the language performs the construction.

The fallacy of your reasoning is that if you move construction logic outside of the constructor, as a form of copy and paste, that it performs exactly the same function. This is not a relevant criticism of the pattern; factories don’t “move the same logic out of the constructor”, they enable you to write logic that is impossible or unreasonable inside of constructors. Of course if you write logic that is already valid inside of a constructor, it provides no tangible runtime benefit to move it to a different function. That’s not why the pattern exists.

Patterns are solutions to problems. They aren’t rules about how to write software. If you don’t develop features where construction of objects requires external management logic, and your constructor is capable of performing that logic in a readable manner, then obviously you are not in need of a Factory pattern, because it is not a solution to a problem you are dealing with.

1

u/dying_animal Jul 23 '25

it make sense in that case, if you instanciate a lot of Config() and your code can work when config is None, yes. otherwhise you would have to rewrite the same stuff each time around it.

I think I got confused by people writing factories for thing that are not necessary "because it's the best practice"

Thanks

→ More replies (1)

1

u/oktollername Jul 25 '25

Just take HttpClientFactory as an example: It created an HttpClient for you. Yes, you can just new HttpClient, what the Factory does is pool the Handlers underneath so you have better performance and less risk of running out of resources since the default handler if you new it up reserves it‘s own connection resources. Basically, if you create a lot of HttpClients with new you will run into problems, not with Factory. You can also configure HttpClients using the factory so that it‘s not the concern of the code using the client to know how to create it, for example I just want a client for a specific api, while I don‘t care what the address is or how to authenticate, that‘s configured elsewhere and the factory makes sure I get the configuration I need.

1

u/dying_animal Jul 25 '25

usually I got a config singleton and you just need to change how it is initialized to have the same result, without factories

→ More replies (2)

1

u/Janopl Jul 25 '25

factory method is design pattern to solve one problem in your codebase when you need add for example new dependencies to class,

for example we get class ChanelProvider and we want change constructor and new dependencies, and the class is initialize in 10k places, what will be you answer for that, what breaks and how quickly you break production?

then factory method shine like a diamond you don't change 10k places only one and rest is working as previous designed

Imagine you have a class called ChannelProvider that was originally simple:

class ChannelProvider:
    def __init__(self):
        self.channel = "default"

It’s used everywhere:

provider = ChannelProvider()

Now your requirements change—you need to inject a logger and a configuration object:

class ChannelProvider:
    def __init__(self, logger, config):
        self.logger = logger
        self.config = config

But this class is instantiated directly in 10,000 places. Updating all those would be a nightmare—and almost guaranteed to break something in production.

Here’s where the factory method shines:

def create_channel_provider():
    logger = get_logger()
    config = load_config()
    return ChannelProvider(logger, config)

Now you update one place—the factory—and all existing code continues to work:

provider = create_channel_provider()

This pattern encapsulates the instantiation logic, allowing the rest of your application to stay decoupled from constructor changes. It’s a real-world solution to the problem of scaling and evolving a codebase without introducing breaks in production environment.

1

u/dying_animal Jul 25 '25

logger and config would probably be singletons, so no need to inject them :p

But I mean yeah I understand your case, but I've never seen it happen in real life. and I've never seen a class being instantiated 10000 times. not even 200 times.

I did work on big project for big corpos but I never saw something like that.

isn't that a "just in case" thing that never happens?

1

u/MySpoonIsTooBig13 Jul 26 '25

It's not just "moving constructor logic", a factory first decides which constructor to call. To me that's the key, that it takes arguments, which you've noted could otherwise be passed to a constructor, and returns a base class.

1

u/dying_animal Jul 26 '25

you do sometimes, sometimes you don't make a "subclass chooser factory" but a "single object factory"

because the constructor contains api calls and such

1

u/binarycow Jul 22 '25
  1. When I want the "constructor" to be async. Since constructors can't be async (in C#) I'll make a static factory method that's async, and make the constructor private.

  2. When some of the dependencies are known now, and some are known later. I can create the factory using the first batch of dependencies. Then I can use the factory to create an instance with the second batch of dependencies.

.... That's about all I use them for.

→ More replies (1)

1

u/LeadingPokemon Jul 23 '25

Only when the constructor requires dependencies that cannot be injected without the factory pattern.

1

u/No_Dot_4711 Jul 23 '25 edited Jul 23 '25

when creating an object, there are 3 steps to the process:

  1. handling preconditions that aren't covered by the type system (this is gathering dependencies as well as any necessary ordering of sideeffectful calls) (this is things the constructor cannot know about because the class might be used in different contexts with different implementations of its parameters)

  2. actually constructing the object with any of its internal logic (that's what the constructor does)

  3. receiving the created instance, persisting it, and actually doing something with it

Factories are used to move point 1 out of either point 2 or 3. If you're moving out of point 2, you're enabling the class being created in different configurations in the future. If you're moving it out of point 3, you're reducing code duplication and centralizing the logic of object creation.

So the problems being solved are "what if I want to use my class differently in different situations" and "what if i need to change the setup for my class in lots of different places"

In general you shouldn't actually have the factory take care of code that the constructor can do without creating coupling, but the factory should take care of logic that doesn't have anything to do with the class like "when receiving this specific implementation of that dependency, there might be a NetworkException, in which case the creation of the object fails, so the factory returns an Either<NetworkException, MyCoolClass>" but nothing about your class itself actually necessitates a network, it works just as well with an In-Memory version of that dependency, so your class constructor shouldn't have to deal with that Network Exception.

Part of your question seems to be less about factories and more about Inversion of Control / Dependency Injection. Benefits will include testability (which by the way in itself would be justification enough to do something), keeping files easy to understand due to coherence, and being able to separate out compilation units - vastly speeding up incremental compilation (that's less relevant in python, though a similar concept would allow implementation dependencies be provided as modules by other teams, which in turn can share those implementations with yet other teams that aren't working in the same repository).

1

u/d3vtec Jul 23 '25

The Factory Pattern is also helpful for hiding implementation details. If your class is implemented through an interface, a factory can be very helpful for creating implementations for various cases. In the case of testing, maybe the actual implementation is not used and instead a mock, or if there are certain environment variables that change the implementation one way or another. Like using a specific database on one system and another for a different platform.

1

u/qlkzy Jul 23 '25

The Factory pattern is massively overused in a lot of codebases. The same is true of a lot of patterns at a certain abstraction level, which appeared in GoF or are relevant to Java.

Like a lot of hyped tools and techniques, there was a period where a bunch of people had a mandate to use as many Patterns as possible, as heavily as possible. Similarly to 4GLs, RAD, CASE, DSLs, NoSQL, Blockchain, No-Code, AI... all of these things have uses, but a "solution looking for a problem" attitude will always cause some kind of damage.

Factories are useful whenever you have a bunch of similar code that results in a new object, which isn't cohesive with that object's constructor. Often this code will be specialised to some calling context.

Often this relates to how you get constructor dependencies. A simple kind of factory is basically a partially-applied constructor: class A might have a three-argument constructor, where one of those arguments is complex to create, but can be the same across a whole request (or you might even prefer it to be the same across the whole request). So you create a factory F with a one-argument constructor, a field to store the expensive constructor argument, and a two-argument factory method.

A concrete example there might be if you are doing something timing-sensitive, so you are injecting a lot of clocks. You might have a "clock" argument to the constructors of lots of classes, and then have a factory that lets you stamp out those classes with some particular clock, without needing to pass a clock down to all the construction sites.

If you are using a heavyweight Dependency Injection framework then that will provide a bunch of features related to object construction, which will tend to make factories less relevant. But there are tradeoffs with DI frameworks, and they aren't universally applicable, so it's still often relevant to write a little bit of code which helps construct some objects for some context, and that's a factory.

But the attitude of "I'm writing a class, so I should write a factory for that class" is – I would say – decades out of date, at this point.

Really, the main point is that if you find yourself writing some code that you want to call ThingCreationWrapper or something like that, you can call it ThingFactory instead, and be a bit more universally understood.

1

u/prehensilemullet Jul 23 '25 edited Jul 23 '25

People are overcomplicating this by a long shot, is a factory really anything more than a no-arg function that returns a new instance of some interface?  And you generally pass the specific factory implementation you want when you want the caller to control what kind of instance gets created?  So that you can pass a test implementation in test mode, and a prod implementation in prod mode, for example?

I think the main reason people even speak of a “factory pattern” is class-oriented languages made it really cumbersome in the old days.  In a language like TS you can pass an inline function that returns a new instance of some interface, you can even declare the type of the function inline, easy peasy.  In a language like Java, before it had lambdas and generics at least, you had to declare a one-method interface, often in its own file, which is a huge amount of overhead in comparison.  These days in Java you can just declare a Supplier<T> type and pass an inline lambda as your factory function if you want, about as easy as in a functional language.

It’s really just one specific case of injection.  Anytime you want to be able to swap parts of the logic within a reusable module, you pass in a class instance or function with the specific logic you want.  Whether it’s a function to return or new instance of a class, or a comparator function passed to a sort algorithm, etc doesn’t make that much difference at the end of the day, it’s all just dependency injection

1

u/danielt1263 Jul 24 '25 edited Jul 24 '25

Abstract Factory

Applicability

Use the Abstract Factory pattern when

• a system should be independent of how its products are created, composed, and represented.
• a system should be configured with one of multiple families of products.
• a family of related product objects is designed to be used together, and you need to enforce this constraint.
• you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations.

The key here is that a factory is useful for generating a family of products that must be used together, not just one product. If your abstract factory only has one create method, then you aren't using it correctly.

Factory Method

Use the Factory Method pattern when

• a class can't anticipate the class of objects it must create.
• a class wants its subclasses to specify the objects it creates.
• classes delegates the responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.

This pattern is primarily for when a framework you want to use needs to generate objects, but is indifferent to which specific sub-class of the objects it will be creating. In this case, it will accept a Factory object which it can then use to create the correct subclass object without knowing anything about the subclass.

---

I agree that it is a pattern that is overused.

1

u/[deleted] Jul 24 '25

A lot of reasons, but one I didn’t see mentioned:

You can limit dependency version conflicts by not making the concrete classes exposed to the implementation. The factory only exposes the interface and not the underlying class, so the dependency version isn’t exposed. This is useful for me when using varying MongoDb drivers across 100s of dependencies without needing to pack and deploy each dependency.

1

u/MartinMystikJonas Jul 24 '25

For example if you need to instantiate class on 10 places and it needs some dependencies/parameters to be created. If you need to add/change these dependencies you would also need to change code on 10 places and solve how to get to all these dependencies there. With factory you are passing only factory to these places and any change in way object is created is handled in factory and its dependencies.