Whether something is considered an anti-pattern often comes down to how a particular design is used. Dependency injection frameworks can provide factories. They are a factory in their own right. DI frameworks are also a kind of service locator, which is a known "anti-pattern." DI frameworks work great when dependencies are known at compile time, or application startup. DI frameworks cannot help you in situations like the user choosing an option from a list in the user interface, and then your code needs to initialize a polymorphic object based on the user selection. Factory methods or factory objects can fill this void.
I've found factory methods or factory objects to be suitable when I need to decide on a concrete type based on information that was not yet available at compile time or application startup. I think there is a distinction between when to use a static method versus a factory object, though. Static methods couple your code to the class that contains the static method. This tight coupling won't hurt anything unless the factory requires outside resources like a file system, database, or web service to do its work. Callers cannot be verified by unit tests, because those outside resources cannot be mocked. That's when factory objects become necessary, because they can be stubbed or mocked for testing purposes.
A factory object works well for use cases where a static factory method is necessary, but introduces too much coupling. You can define an interface for the factory, which you can configure at application startup using — you guessed it — a dependency injection framework. The other objects your factory requires can be injected into the factory at the time it is created, and before the factory gets injected into another object where use case specific information is combined with preconfigured dependencies to create a polymorphic object at runtime. That's a mouthful! And certainly not the ideal solution for all your object creation needs.
DI frameworks, static factory methods, and factory objects all have their use cases. A perfectly fine design pattern can quickly become an anti-pattern when used in an inappropriate situation. DI frameworks, builders, abstract factories, singletons — they are all tools in your tool belt. Use them when it makes sense. Use a different tool when it doesn't make sense. None of those tools completely replace the others. There is some overlap in how they are used. Sometimes one tool is more specialized than the others and works best in a limited number of use cases where other tools would work in a less elegant fashion.
One of the things he suggested was to prefer public static factory methods instead of public constructors.
Again, you can over apply anything. That statement is a broad generalization that I would be wary of. Remember that constructors are static methods that many languages require you to prefix with the new
keyword. I answered a question recently about builders returning factories. It was a misapplication of two good patterns. If you read the comments below my answer, you will quickly discover the OP was writing code to dance around calling a constructor without needing any of the benefits that more complex object creational patterns provide.
You will need to understand the problems various design patterns solve to know when it is appropriate to apply them. Misapplying them is the anti-pattern.
There has been a lot of follow-up comments on answers to this question. Perhaps an illustration would help clear this up.
DI frameworks are the Swiss Army Knife of object creation. They work for a lot of scenarios. Factories and builders are more like a hammer. They are a more specialized tool. Please pardon the abuse of an old adage:
When all you have is a hammer, everything looks like a nail. But when you've become accustomed to your Swiss Army Knife always having a suitable tool, don't be afraid to reach for a hammer when you have a nail to pound.