I'm trying to understand the Factory Method pattern. I've managed to distinguish it from the Simple Factory, but now I don't get why it's actually called a "pattern". Please, look at my example below:
Class Diagram link
Sample java code for Messenger:
public String exchangeMessages(String messageToSend) {
Socket socket = getSocket();
socket.open();
socket.send(messageToSend);
String receivedMessage = socket.receive();
socket.close();
return receivedMessage;
}
And for Client:
public static void main(String[] args) {
Messenger messenger = new TCPMessenger("127.0.0.1", 4321);
String result = messenger.exchangeMessages("Hello!");
System.out.println(result);
}
If I understand correctly, everything makes sense because exchangeMessages
method exists. We use the abstract factory method getSocket
inside it and thanks to it we:
let subclasses decide which class to instantiate
But isn't it just an ordinary abstract class implementation? We take advantage of the code shared by both TCPMessenger
and UDPMessenger
- for me, this is not a pattern but a core feature of Object-Oriented Programming that everybody knows from the beggining of OOP language learning!
Moreover, I think that naming this creational is very confusing. We actually care about exchangeMessages
method, so Client
(part of the code that uses our "pattern") is not even aware of the Socket
class which creation we're all about. It's more like a way to implement Messenger
functionallity (which can be easily extended etc...) than a way to really create something.
Am I missing the point or is my example invalid? Please guys, let me know what do you thing about it.
Thanks in advance!
The Factory Method pattern is a simple pattern, but still a pattern nonetheless.
Your Client
and its relationship to the Factory Method
The Gang of Four (GoF) definition of the Factory Method Pattern does not specifically mention a Client
as a participant of the pattern itself. In reality the Client
is most likely to use the Factory Method indirectly through some other operation.
In your case as the Client
does not care about the Socket
being used, but just the Messenger
itself. However, the Messenger
is dependent upon a Socket
as it has some behavior that uses a Socket
Object.
So whilst the Client
itself does not care about the Socket
, it does care about the Messenger
which has a use dependency with Socket
.
As the Socket
itself is abstract it gives us a problem, as we don't want to replicate the same logic in exchangeMessages(String)
multiple times for the different implementations of Socket
(TCPSocket
and UDPSocket
), especially when we may want to add more Socket
classes at a later date.
This is where the Factory Method pattern comes into play, as we can define all the generalized behavior for exchanging messages at an abstract level, but leave the creation of the actual Socket
implementation (TCPSocket
and UDPSocket
) to subclasses of Messenger
(TCPMessenger
and UDPMessenger
).
Discussion of alternatives to the Factory Method Pattern
You could just set the Socket
as a field of Messenger
, and inject it using a Strategy pattern approach or have a constructor that takes a Socket
as a parameter. A drawback of this approach is that we'll have to maintain a reference to this Socket
Object as a class field in anticipation of it's use.
However, with the Factory Method Pattern, the Socket
will only be created in the method exchangeMessages()
when needed and then discarded when the method terminates, which may be of some benefit. This comes at the cost of having to create one of the Socket
Objects each time exchangeMessages()
is called, which may not be ideal.
You could also pass the required Socket
to the exchangeMessages()
method to be used, but this may not as convenient for the user of the method in the long term.
If your Messenger
subclasses also have some specific behaviors (new methods / overridden implementations) not applicable to all types of Messenger
, then Factory Method is certainly the way to go, as we need to subclass Messenger
anyway and it allows us to strictly enforce the type of Socket
created by the Factory Method getSocket()
.
Perhaps others could contribute to the pros/cons of the Factory Method (specifically in Java as this the language tag for the question) and I can update this answer in due course.
Validity of your example
About whether your example is invalid or not. I think it helps to first fully understand the pattern and the important classes, operations and relationships in order to conform to the Factory Method pattern (as specified by the GoF).
The Factory Method Pattern allows you to define an Operation (or possibly several operations) in an abstract Creator class (in your case Messenger
) which will use some Object (a Product [Socket
]) without knowing the specific Product in advance and deferring its creation (hence the term creational pattern) to the Factory Method.
The Factory Method itself (getSocket()
) is abstract in the Creator class and will be implemented by Concrete Creators (TCPMessenger
, UDPMessenger
) so polymorphism is used to achieve Object creation.
The Factory Method will return a Concrete Product (TCPSocket
, UDPSocket
) and have a return type applicable to all Concrete Product classes (Socket
) used by the Operation in the abstract Creator class.
The Operation(s) (exchangeMessages(String)
) that use the Factory Method will use the Concrete Product returned by the Factory Method by the interface Product which is applicable to all Concrete Product classes (Socket
).
The result is that this pattern allows new Concrete Product classes to be added by implementing / subclassing the Product interface / class (or its subclasses...) and introducing a new Concrete Creator which returns the newly added Concrete Product from its Factory Method, preventing the need to re-write your Operation(s) that use this Product.
This means that we do not need to modify existing code when introducing new Concrete Products (Open/Closed Principle).
Generalized UML for the Factory Method Pattern
Some notes on the UML:
factoryMethod()
can be given a default implementation in Creator
(i.e. a default Product
to return), in turn allowing Creator
to be non-abstractfactoryMethod()
could be public
if desired, but this is superficial to the intention of the pattern since the factoryMethod()
is primarily intended to be used by operation()
Product
does not have to be abstract class, it could be an interface or it could be a concrete classValidity of your example (continued)
In reference to the UML (and your example), the important parts of the pattern in less wordy terms are as follows:
There must exist
Product
interface (not neccesarily an interface in Java terms, could be a class or abstract class in reality) (in your case Socket
)ConcreteProduct
classes that implement the Product
interface (TCPSocket
, UDPSocket
)Creator
class (Messenger
)Product factoryMethod()
method that is defined in the Creator
class (getSocket()
)Note: The Creator
and factoryMethod()
are usually abstract, but the Creator
can define a default Product
removing this requirement.
operation()
methods in the Creator
class that use the ConcreteProduct
returned by the factoryMethod()
(exchangeMessages(String)
)ConcreteCreator
class (TCPMessenger
and UDPMessenger
))Such that
ConcreteCreator
classes implement the Product factoryMethod()
to create and return a ConcreteProduct
Creator
class uses the ConcreteProduct
(returned by Product factoryMethod()
) through the interface for all Product
implementationsThe last two points reflect that Creator
has a use dependency with the Product
interface, and the ConcreteCreator
classes have a create dependency with its corresponding ConcreteProduct
class.
Again, note that the Client
class is not part of the pattern itself (as defined by the GoF).
So in conclusion, your example would appear check out as the Factory Method in regards to the requirements listed above if the TCPMessenger
and UDPMessenger
class implement the getSocket()
method correctly (which I assume they actually do).