One AbstractFactoryClass to Rule them, one AbstractFactoryClass to find them, and in the Abstraction, bind them.

Who is he? Why he's me of course.,design patternstypescriptYu-Gi-Oh!

Couple of bits to blurt out and then I'll do the usual questioning in type process. I'm learning as I type so I hope you may find this useful if you are new to this design pattern.

The gpt overview for the Factory Pattern (FP) is: about creating objects without specifying the exact class to create. Think of it as a manager that delegates the task of creating an object to sub-classes.

Couple of key components that make up the FP implementation:

  1. Factory Method: An abstract method in the parent class. And then sub-classes implement this method to return an object. I think this ties into the _about create objects without specifying the exact class to create. _
  2. Concrete Factory: Each subclass that extends the parent class (the one that has the abstract method that returns an object) becomes a concrete factory that produces objects.
  3. Product: What the factory creates. The product is usually an interface, and concrete products are the implementations.

Alright so lets go through the steps.

We need to create our factory method.

A factory method is an abstract method in a class ( which will be a parent class), meaning other classes will inherit from it and become sub-classes.

This will define what ultimately gets produced( the object being returned).

Ok so lets say we want to create some logic to create Yu-Gi-Oh! decks.

The factory method will exist in an abstract factory class:

abstract  class  DeckFactory {

abstract  createDeck():  Deck

}

A quick note on the word abstract here:

Abstract class - a class that cannot be instantiated on its own and acts solely as a blueprint. You define methods in it that any subclass that extends it MUST implement.

Ok so any class that extends DeckFactory must implement a createDeck method, which must return type Deck.

Ok so what is type Deck?

This really skips to point 3, the product. Type Deck is what the factory ultimately produces. Lets write that now.

interface Deck {
	cardCount: number;
	drawCard():number;
	}

Alright so we have a Factory Method and a Product .

So now we need 2. a Concrete Factory. So as above, this is a subclass of the abstract class that tells us what we must produce. Hence I believe the part of gpt's generalisation:

A manager that delegates the task of creating objects to sub classes.

The manager here is the abstract method/class that we created for point 1 - Factory Method. The "delegated task" is the actual instantiation of Deck objects(products). And the "sub-classes" are the concrete factories.

Ok so lets make these Concrete factories.

class PredaPlantDeckFactory {

}

Happy days right? Not quite yet. This factory doesn't yet know what it needs to produce. How do we tell it what to produce. We make it a sub-class of the abstract class.

class PredaPlantDeckFactory extends DeckFactory {
	// we have a deal that you must produce what I tell you, and that is decks.
	createDeck(): Deck
}

To recap. We have a manager. The manager is the DeckFactory. The manager doesn't actually do any work, but just tells the subordinate factories what to produce. So now we have a factory that says ok I want to create PredaPlantDecks. Fine says the manager, inherit/extend me and we've got a deal.

So the manager turns up at the PredaPlantDeckFactory and says nice show me around.

PredaPlantDeckFactory says you told me to create decks, so I've implemented this createDeck method and it returns a Deck just like you said.

However, the manager then says that's all well and good, but you're meant to be actually producing something concrete. You're a concrete factory after all. But all you've done is say I've got a method and it will return a product, and it will be of type Deck. (this actually gives you an error in your editor) You don't actually produce any products yet!

ah fuck.

So we need to go back to our implementation of PredaPlantDeckFactory implementation:

class PredaPlantDeckFactory extends DeckFactory{
	createDeck(): PredaPlantDeck{
		return new PredaPlantDeck()
	}
}

There now we have a method that returns PredaPlantDeck type.

Manager / DeckFactory walks in says ah ok now you're actually producing something concrete. A concrete product. What's a PredaPlantDeck? And how do I know it's what I told you to produce (return) - a Deck?

Ah fuck again.

Ok distract the manager, and quickly spin up the class for a PredaPlantDeck. And for god's sake make sure it is bound by the Deck interface!

class PredaPlantDeck implements Deck {
	cardCount:  number  =  50
	drawCard():  number {
		return  1
	}

Great. Now the manager sees that the Concrete Factory produces a Concrete Product which is a type of Product. The manager is happy because the concrete factory is implement the Factory Method set out in the abstract class.

This can be represented graphically as such:

or with our example:

So what's the point?

If we go back to what gpt said about this pattern, it is : about creating objects without specifying the exact class to create. Think of it as a manager that delegates the task of creating an object to sub-classes.

If you really chew on this we can basically say at the Deck Factory ( FactoryMethod ) level what many different factories will produce, without ever having to actually specify the actual class to create. So here we may have many more different X-deckFactories, say at a tournament. And they will each produce their own decks (Products) but with some control on those decks set out by the Deck (Product) interface.

So if we had a collector's meeting, we could each define a ConcreteFactory for each deck, and each deck could be created for each owner, all according to the same specification. So say 5 people have Preda decks, we could use the PredaPlantDeckFactory to produce five PredaPlantDecks each with different owners. Maybe with their own custom properties depending on how we define PredaPlantDeck class, but at least we know it will be a valid Product (Deck).

Ok well that's my attempt at unpacking something completely unknown in one day. Any comments or feedback or corrections I would absolutely love to hear them - @kolyaD3v (opens in a new tab)

bisous.