4

From GoF chapter about the Factory Method pattern:

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

The idea is to let subclasses decided which class to instantiate, and GoF's implementation of the idea, is to provide an abstract method in the superclass, that subclasses need to override, and thus providing their own instantiation logic.

What I don't understand is, why implementing it using an abstract method, and not using a class member which is the factory. I'll explain.

This is the GoF way:

public abstract class Creator { public void doStuff() { Product product = createProduct(); /* etc. */ } public abstract Product createProduct(); } 

Usage:

 MyCreator myCreator = new Creator() { @Override public Product createProduct() { return new MyProduct(); } } myCreator.doStuff(); 

But why bother with the subclassing, etc.? I suggest this approach:

public class Creator { private Factory factory; /* constructor */ public Creator(Factory factory) { this.factory = factory; } public void doStuff() { Product product = factory.createProduct(); /* etc. */ } } 

And this is how you use it:

 MyFactory myFactory = new MyFactory(); Creator creator = new Creator(myFactory); creator.doStuff(); 

So what is the benefit in GoF's approach? Why not composing the Factory into the Creator class instead of expressing it using an abstract method?

1
  • It is because you want to share the common code among all concrete factories in abstract class above. Now what you are doing is right but then how do share/inherit common code among your factories ? Hence using abstract class in more flexible. Commented Jul 20, 2020 at 19:57

4 Answers 4

5

Why not composing the Factory into the Creator class instead of expressing it using an abstract method?

Because in that case the client "knows" what Factory class to instantiate which defeats the whole purpose of the pattern. The whole idea is that the client is oblivious as what factory is built, it only makes a call to an Abstract class. Think that you plugin-in to your framework some third party factory provider and you have no idea what they instantiate (and also don't care) as long as serves the purpose.

Sign up to request clarification or add additional context in comments.

2 Comments

Thats a wrong answer. The client always know the concrete factory. It just does not know the concrete product being created.
If the client was modified so that it was an injected an abstract representation of the factory (meaning Factory would implement a certain interface), does that then make this something that follows the Factory Method pattern? Or Abstract Factory pattern?
4

The Factory Method Pattern is used to give subclasses control over the type of object they generate. In your case, it is not the subclass that controls the type of object but the user of the class.

The following example is copies from the Wikipedia entry on the Factory Method Pattern. We have a maze game which exists in two variants: the normal maze game and a magic maze game with adapted rules. The normal maze game consists of normal rooms and the magic maze game of magic rooms.

public class MazeGame { public MazeGame() { Room room1 = makeRoom(); Room room2 = makeRoom(); room1.connect(room2); this.addRoom(room1); this.addRoom(room2); } protected Room makeRoom() { return new OrdinaryRoom(); } } public class MagicMazeGame extends MazeGame { @Override protected Room makeRoom() { return new MagicRoom(); } } 

By using the Factory Method Pattern we can make sure that the MagicMazeGame consists of MagicRooms but we can still re-use parts of the superclass.

In your suggestion the MazeGame class would be changed to:

public class MazeGame { public MazeGame(RoomFactory factory) { Room room1 = factory.makeRoom(); Room room2 = factory.makeRoom(); room1.connect(room2); this.addRoom(room1); this.addRoom(room2); } } 

and now it would be possible to do:

MazeGame game1 = new MazeGame(new MagicRoomFactory()); MazeGame game2 = new MagicMazeGame(new OrdinaryRoomFactory()); 

which is something you would like to prevent because then MazeGames with the wrong kind of rooms in it can be created.

2 Comments

Why do we need to prevent this? the last section of the code I mean
@Tony Lin: Because then a MazeGame would have the wrong kind of rooms in it. (I edited the answer to make this point more clear.)
2

its often useful in these types of situations to use actual English types for illustrations rather than more abstract terms like "Product"

So, let's take Pets, and say that every (sub-)type of Pet has a Home (eg. Dog has a Kennel).

For your example, we would have :

Public void doStuff() { Home home = factory.createHome(); } 

But in this case, where does the logic go that says Dogs get Kennels, and Birds get Cages? It would have to go in the factory object - which in turns means that the inheritance hierarchy of Pets would have to be explicitly repeated in the Factory logic. This in turn means that every time you add a new type of Pet, you'll have to remember to add that type to the Factory as well.

The factory method pattern means that you'd have something like :

public class Pet { private String name; private Home home; public Pet(String name) { this.name = name; this.home = this.createHome(); } public abstract Home createHome(); 

This allows that every time you create a new type of Pet, you can specify that Pet type's home without having to change any other class, and in the process also know that every Pet type DOES have a Home.

Eg. You would have :

public class Dog extends Pet { public Home createHome() { return new Kennel(); } } 

Edited to add Dog example

Comments

1

I think that the answers to this question aren't totally satisfactory, so here's my two cents...

To quote @Hoopje's answer, we might end up with something like this:

public class MazeGame { public MazeGame(RoomFactory factory) { Room room1 = factory.makeRoom(); Room room2 = factory.makeRoom(); room1.connect(room2); this.addRoom(room1); this.addRoom(room2); } } 

and then

MazeGame game1 = new MazeGame(new MagicRoomFactory()); MazeGame game2 = new MagicMazeGame(new OrdinaryRoomFactory()); 

As has been discussed above, this is nonsensical. However, I would contend that those last two lines don't make sense anyway, because in the OP's opinion, you would never need to create a MagicMazeGame at all. Instead you would just instantiate a MazeGame passing in new MagicRoomFactory().

MazeGame magicOne = new MazeGame(new MagicRoomFactory()); MazeGame normalOne = new MazeGame(new OrdinaryRoomFactory()); 

However, let's imagine that our MazeGame has multiple factories. Let's say that as well as needing to have a room factory, it also needs to have a points factory, and also a monsters factory. In this situation, we might end up with all of this being forced into the MazeGame constructor, like this:

public MazeGame(RoomFactory rmFactory, PointsFactory pointsFactory, MonsterFactory monstersFactory) 

This is fairly convoluted, and instead it would be better to create concrete subclasses that each control their own type of game. That long constructor looks like a code smell to me too, though someone more knowledgeable might be able to add to this.

What's more, this means that whichever object is instantiating the game has to know about all of these inner-working classes, which breaks encapsulation. All in all, by doing it this way we are giving too much control to the client, who doesn't want to know about all of these implementation details.

That's how I see it anyway...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.