When to use the abstract factory pattern?
Asked Answered
T

3

18

I'm trying to succinctly describe when to use a factory, for both myself and my team. I ran across the following related questions, which helped somewhat:

Based on these links, and a bunch of other sources (listed at the bottom), I've come up with the following:

When to use the abstract factory pattern:

  • when you use an interface var or the 'new' operator
    • e.g. User user = new ConcreteUserImpl();
  • and the code you are writing should be testable / extensible at some point

Explanation:

  • interfaces by their very nature imply multiple implementations (good for unit testing)
  • interface vars imply OCP- and LSP-compliant code (support sub-classing)
  • use of the 'new' operator breaks OCP/DI, because highly-coupled classes are hard to test or change

"Do I create a factory for every object type? That seems excessive."

  • no, you can have one (or a few) factories that produce a lot of (usually related) object types
  • e.g. appFactory.createUser(); appFactory.createCatalog(); etc.

When NOT to use a factory:

  • the new object is very simple and unlikely to be sub-classed
    • e.g. List list = new ArrayList();
  • the new object is not interesting to test
    • has no dependencies
    • performs no relevant or long-running work
    • e.g. Logger log = new SimpleLogger();

References:


My question is: is my summary accurate, and does it make sense? Is there anything I've overlooked?

Thanks in advance.

Thomsen answered 2/12, 2010 at 2:41 Comment(1)
I hate reviving old threads, but... I disagree that loggers should be new'd up as above. I often run different loggers in different test environments. I configure the environment to use a specific logger and inject it into objects that log. (I might even inject arrays of loggers.)Hedvig
S
5

I'd also say don't use a factory when you have a particular implementation that you want. To continue the List example, I know that I want an ArrayList because I'm doing random access. I don't want to rely on a factory getting this right when I can do it myself.

Conversely, when I don't want to know about the concrete subclass then I can use a factory and let it worry about which object to actually instantiate.

I guess I'd suggest that you add a bullet to the "when to use the abstract factory pattern" that says "and you don't really care which concrete subclass you get", and the converse to "when not to use a factory".

EDIT: Be careful to avoid the general-purpose tool-building factory factory factory.

Steepen answered 2/12, 2010 at 2:51 Comment(2)
Ok - let's say I wanted the specific advantages of a cached thread pool: ExecutorService pool = Executors.newCachedThreadPool(); However, in my unit tests (for whatever reason) I'm not interested in the results of the work done in the pool, and I don't want to have to wait for the work to finish every time I run my tests. Wouldn't I then still use a factory so I could stub / mock out my thread pool for tests? It seems to me that when you consider testing, you want to think of most of your code as not caring about the actual implementation lest you write untestable code.Thomsen
Yes, that's correct. Generally most of your code doesn't care about the actual implementation. Choosing between ArrayList and LinkedList is one of the few times that you do care because they have different performance characteristics. You're right: for testing it's best to ignore the actual implementation as much as possible.Steepen
Y
3

In general, use it when you want to be able to switch of implementation by external configuration.

JDBC and JAXP are excellent examples. For more examples, check this answer.

Youngling answered 2/12, 2010 at 3:2 Comment(3)
Would not that mean to use an IoC container?Soffit
could you please elaborate on when you would use your custom factory vs an IoC for switching object type by config?Soffit
@Max: depends if the API is to be run on an IoC container or not.Youngling
S
1

Abstract Factory pattern provides with a way to encapsulate concrete factories that share some commonality with each other, meaning they implement same interface/abstract class.

You need to use factory pattern whenever you want to control the initialization of your objects, instead of giving the control to the consumer.

Soffit answered 2/12, 2010 at 2:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.