Quantcast
Channel: What are the differences between Abstract Factory and Factory design patterns? - Stack Overflow
Viewing all articles
Browse latest Browse all 22

Answer by a2k42 for What are the differences between Abstract Factory and Factory design patterns?

$
0
0

In my estimation the answer given by @TomDalling is indeed correct (for what it's worth), however there still seems to be a lot of confusion in the comments.

What I've done here is create some slightly atypical examples of the two patterns and tried to make them appear at first glance quite similar. This will help to pinpoint the crtical differences that separate them.

Factory MethodAbstract Factory

If you're completely new to the patterns these examples are propably not the best place to start.

Factory Method

enter image description here

Client.javaish

Client(Creator creator) {    ProductA a = creator.createProductA();}

Creator.javaish

Creator() {}void creatorStuff() {    ProductA a = createProductA();    a.doSomething();    ProductB b = createProductB();    b.doStuff();}abstract ProductA createProductA();ProductB createProductB() {    return new ProductB1();}

Why is there a Creator and a Client?

Why not? The FactoryMethod can be used with both, but it will be the type of Creator that determines the specific product created.

Why isn't createProductB abstract in Creator?

A default implementation can be provided, subclasses can still override the method to provide their own implementation.

I thought factory methods only create one product?

Each method does return just one product, but the creator can use multiple factory methods, they just aren't necessarily related in any particular way.

Abstract Factory

enter image description here

Client.javaish

AbstractFactory factory;Client() {    if (MONDAY) {        factory = new Factory2();    } else {        factory = new AbstractFactory();    }}void clientStuff() {    ProductA a = factory.createProductA();    a.doSomething();    ProductB b = factory.createProductB();    b.doStuff();}

Wait! Your AbstractFactory isn't, well... er Abstract

That's okay, we're still providing an interface. The return types on the create methods are super-types of the products we want to make.

Holy Smoke Batman! Factory2 doesn't override createProductA(), what happened to "families of products"?

There's nothing in the pattern that says an object can't belong to more than one family (although your use case might prohibit it). Each concrete factory is responsible for deciding which products are allowed to be created together.

That can't be right, the Client isn't using dependency injection

You've got to decide what your concrete classes will be somewhere, the Client is still written to the AbstractFactory interface.

The confusion here is that people conflate composition with dependency injection. The Client HAS-A AbstractFactory regardless of how it got it. Contrast with the IS-A relationship, Client and AbstractFactory have no inheritance between them.

Key Differences

  • Abstract Factory is always about families of objects
  • Factory Method is just a method that allows subclasses to specify the type of concrete object
  • Abstract Factory provides an interface to a Client and is separate from where the products are used, the Factory Method could be used by the Creator itself or exposed to a Client.

Summary

The purpose of a factory is to provide a objects, either to a client or itself.

A creator has its own responsibilities and may need to use objects or pass them to a client

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. - GoF

An abstract factory only:

Provide[s] an interface for creating families of related or dependent objects without specifying their concrete classes. - GoF


PlantUML code if you want to play with the diagrams:

@startuml FactoryMethodabstract class Creator {    creatorStuff()    {abstract} createProductA(): ProductA    createProductB(): ProductB}class Creator1 {    createProductA(): ProductA}class Creator2 {    createProductA(): ProductA    createProductB(): ProductB}together {    interface ProductA {        doSomething()    }    class ProductA1' class Product1B}together {    interface ProductB {        doStuff()    }    class ProductB1    class ProductB2}Client --> CreatorCreator <|-- Creator1Creator <|-- Creator2Creator --> ProductB1ProductA1 <-- Creator1ProductA1 <-- Creator2ProductB2 <-- Creator2ProductA <|.. ProductA1ProductB <|.. ProductB1ProductB <|.. ProductB2ProductA <- Creator@enduml
@startuml AbstractFactorytogether {    interface ProductA {        doSomething()    }    class ProductA1}together {    interface ProductB {        doStuff()    }    class ProductB1    class ProductB2}class AbstractFactory {    createProductA(): ProductA    createProductB(): ProductB    --    -}class Factory2 {    createProductB(): ProductB}Client --> AbstractFactoryAbstractFactory <|-- Factory2ProductA <|.. ProductA1ProductB <|.. ProductB1ProductB <|.. ProductB2AbstractFactory --> ProductA1AbstractFactory --> ProductB1ProductB2 <-- Factory2@enduml

Viewing all articles
Browse latest Browse all 22

Trending Articles





<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>