23

I consider Joshua Bloch's Effective Java the best book on the language that I read. However, I started to wonder about something

One of the things he suggested was to prefer public static factory methods instead of public constructors. He mentioned, among others, two advantages

  • a factory method doesn't have to create a new instance each time, instead it can return cached instances
  • a factory method can return any subtype of its return type providing more flexibility

But isn't that all a dependency injection (DI) concern?

It made total sense when I was only learning Java, but now I start to look at it differently. Managing instances, returning proxies, it's what DI frameworks like Spring or Dagger do. Should we really allow Bloch's "embedded DI" in our classes in addition to (let alone in place of) that framework-based DI?

Did "factory methods" become an anti-pattern, as singletons did (and for a similar reason -- we decided to delegate instance management to DI frameworks to provide a better separation of concerns)?

    // here, Dagger is all alone responsible for instance management
    @Provides
    @Singleton
    public MyClass myClass() {
        return new MyClass("My Class Instance", 42);
    }
    // here, instance management may be performed by both Dagger and the class itself
    @Provides
    @Singleton
    public MyClass myClass() {
        return MyClass.of("My Class Instance", 42);
    }
5
  • 1
    Related: Usage - Factory Pattern vs Dependency Injection
    – Doc Brown
    Commented May 24 at 12:56
  • or How much is too much Dependency Injection?
    – Doc Brown
    Commented May 24 at 13:01
  • 5
    For the record, singletons aren't considered an anti-pattern because DI containers appeared and took over instance management, but because (1) a singleton is a global, and (2) it is often haphazardly used directly inside classes and methods, hindering your ability to inject a different subtype. This is also why the Service Locator is considered an anti-pattern - and it's easy to use DI containers as service locators. A big contribution to the anti-pattern status comes from how often people are likely to misuse the pattern. Commented May 25 at 12:32
  • 1
    It's best to think of static factories as of more flexible constructors that can have a more informative name. Sometimes, you need those. As for the other bullet point "a factory method can return any subtype of its return type providing more flexibility" - this sort of thing is probably better utilized not for DI (where you inject the subtype), but for doing some OO version of a functional programming–style ADT. Commented May 25 at 12:41

5 Answers 5

28

But isn't that all a DI concern?

No, it isn't. Raw DI simply means that an object receives its dependency as parameter, as opposed to constructing it internally. You inject dependency.

It is true that modern DI frameworks do a lot more. In fact these implement more patterns, including factory pattern. Except it is hidden behind fancy semantics. Those annotations are converted into factories behind the scene. Factories are there, except are hidden.

The same in fact applies to singletons. These are not anti pattern, and in fact @Singleton annotation tells the framework to treat it as singleton. So maybe you still can instantiate the class manually, but as long as you let the framework manage it, then you have a singleton. Note that the singleton pattern doesn't mandate how this single instance is constructed (that is very language specific anyway), only that a given class has single instance. That's all.

Also using a DI framework requires... a DI framework. Obviously. Maybe you don't want such overhead. Assuming your dependency tree is not insanely complicated, it is arguably easier to write simple factories. And often hundreds of times faster at runtime. Well, to be honest I don't know much about Java, from what I read it seems that Dagger has a decent performance since it constructs underlying factories at compile time instead of runtime. Still there must be some performance hit, such framework has to be conservative, e.g. always enforce thread safety, even if it is not needed. And if Dagger claims to be thread safe (which seems to be the case) then this has to be done at runtime. I'm sure of it, because thread safety is not detectable at compile time in general.

Regardless, it is coupling. Often unnecessary. Note that typically it is easy to wrap a factory with a DI framework (although as I already mentioned I don't know much about Java). But if you hard couple your code with concrete DI framework then you have a problem: what if I want to use it in a project that uses different DI framework? Or no DI framework at all? So if I was supposed to write a standalone lib then I would completely avoid using a DI framework in favour of factories. Even with complicated dependencies. And in fact in my 10+ years of experience I did exactly that and it worked fine.

22
  • 11
    @demavi I'm not sure what starts where. Thousands of small libraries expose small factories instead of coupling with heavy DI frameworks. There is absolutely no need to use it everywhere. In fact I would call it a bad practice.
    – freakish
    Commented May 24 at 7:45
  • 11
    @demavi I don't know what you mean by "framework" here. Writing a factory is nothing even close to writing a full DI framework. And I've never said you should write a DI framework. That's not even a topic here.
    – freakish
    Commented May 24 at 7:53
  • 11
    @demavi you keep repeating the same claim, without backing it up with any facts. Its the opposite, I already explained to you that vast majority of small libraries don't incorporate DI frameworks, but they use factories. Pick a library at random and see for yourself. They never end up in a place where they need it. Never. And its good thing, small modules is a good practice. In fact, why do you think "YAGNI" acronym exists?
    – freakish
    Commented May 24 at 8:22
  • 10
    Note that it is very easy to add DI framework to an existing project. But not so easy to get rid of it.
    – freakish
    Commented May 24 at 8:33
  • 19
    It’s worth considering that if your dependencies are so complicated that only a DI framework can maintain them that maybe what you need isn’t a framework that enables this design. Maybe you need a better design. Commented May 24 at 10:06
6

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.

11
  • 1
    That sounds like an organizational or skill deficiency, rather than a problem with the patterns themselves. The "wrong direction" wasn't "failure to use a DI framework from the start", but "failure to recognize the growing complexity and tame it while it was still manageable".
    – Mac
    Commented May 25 at 15:50
  • 2
    @demavi - DI is a design technique - it existed as a concept (and a practice) before DI frameworks were invented. DI frameworks just help manage the lifetimes, and abstract away the actual process of wiring up dependencies. In principle (and sometimes in practice), you can do the wiring manually. All that is not the point of DI. The point is to design the classes so that the dependencies are explicit, and specified in terms of the most appropriate abstract type, so that you can pick and choose the implementation. Sometimes, a dependency happens to be a factory (object or a function). Commented May 25 at 16:57
  • 1
    @kapex: you cannot call a constructor from an instance of an object. You must specify the class name. To me, that makes a constructor static from the perspective of the caller. This is echoed in other languages, too. In Ruby, constructors are literally a static method called new. You call new Foo() in Java, but Foo.new() in Ruby (if we dismiss the fact that classes in Ruby are also objects). In Python, you call Foo() without a special keyword. Again, no object exists to provide context. The constructor is static. Commented May 26 at 13:10
  • 1
    @GregBurghardt ok, I guess from the caller's perspective that makes sense, the constructor is called without needing a prior instance. The caller does instruct the creation of an instance though. From the perspective of the constructor an object context exists; memory has already been allocated during execution of the the class instance creation expression (e.g. new Foo()) and it can access instance fields and methods of this, which makes more like an instance method to me. But I guess it might not make sense to categorize constructors as class or instance method too strictly.
    – kapex
    Commented May 26 at 14:56
  • 1
    I can see your point. Constructors can be considered static from the caller's perspective, but they are an instance method from the perspective of the constructor itself. Commented May 26 at 21:50
1

This is how is going: constructor, factory, dependency injection where dependency injection uses factories that use constructors.

To address both questions dependency injection supports different scopes of the instances it "knows" including singleton scope.

Neither of the two are anti-patterns. My opinion. Probably it could be twisted in unbeknown ways the same way everything could be though that's not what design patterns and programming principles are about.

0

DI just for IO objects, why? Because you can change the implementation depending on the scope, integration test, new technology, etc. Everything else is likely okay to not have reference transparency,e.g domain objects like aggregators, domains services, etc. Unless you need it, then you apply specific pattern, like strategy.

0

The only anti-pattern here is the use of a DI framework, Spring Framework being the worst. Precisely because it leads to uncontrolled accidental complexity.

Typically developers' perception of how much more robust software without such frameworks can be, is based on the codebase they work with in a big corporation - the leap is too big from their daily reality to even imagine the possibility of not using Spring or whatever DI framework.

5
  • 3
    I don't have enough rep here to downvote, but to be frank, this is a bit of FUD. DI frameworks like Spring are just tools. Can they be sharp and dangerous? Of course. Can they be extremely useful and increase efficiency? You bet. A 2hp chainsaw can be extremely dangerous if you don't use it right, but it's going to make far quicker work of that downed tree than your old hand saw.
    – Mac
    Commented May 25 at 15:56
  • 1
    The DI framework can only provide you with capabilities. It is the engineer who decides how to use those capabilities. This answer sounds like a case where developers make an interface for everything, even in circumstances where it doesn't make sense just because somebody said "best practice". The DI framework was just the medium through which these design decisions were made. Removing the DI framework, sadly, doesn't remove bad design decisions. Commented May 25 at 16:36
  • That's kind of the definition of anti pattern, too many dev misusing a pattern, and DI in particular spring is getting very close to that Commented May 25 at 23:06
  • Worst, I've seen some dev that don't know how to instantiate or architecture anything because the only thing they knew was 1 DI framework Commented May 25 at 23:10
  • 1
    This is an answer to the question "are DI frameworks a good pattern", not to "are factory methods an anti-pattern". Even as an answer to the first question, this misses various points, such as the ability to easily adapt the factories to the environment the code is running in (dev, testing, production) and others.
    – toolforger
    Commented May 27 at 9:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.