Dead factory – Alexander Kaiser – This file is licensed under the Creative Commons Attribution 2.0 Generic license.
The Factory Method pattern is, in my opinion, one of the most useful creational design patterns.
It allows us to delegate the creation of an object to a dedicated class, and thus encapsulate all the logic of this creation that is often not directly related to the responsibility of the class.
1) Simple example :
Given the following code :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace Oinant.Blog.Factory.SimpleExemple | |
{ | |
public class MyBusinessObject | |
{ | |
private string _content; | |
private DateTime _dateTimeReleventToBusinessLogic; | |
public MyBusinessObject(Tuple<DateTime, String> creationData) | |
{ | |
_content = creationData.Item2; | |
_dateTimeReleventToBusinessLogic = creationData.Item1; | |
} | |
public bool IsBusinessRequirementMet() | |
{ | |
return !string.IsNullOrEmpty(_content); | |
} | |
public void PerformBusinessLogic() | |
{ | |
} | |
public string GetContent() | |
{ | |
return _content; | |
} | |
} | |
class MyBusinessObjectFactory | |
{ | |
private readonly IBusinessRepository _businessRepository; | |
public MyBusinessObjectFactory(IBusinessRepository businessRepository) | |
{ | |
_businessRepository = businessRepository; | |
} | |
public MyBusinessObject Create(Guid id) | |
{ | |
var content = _businessRepository.GetContent(id); | |
return new MyBusinessObject(new Tuple<DateTime, string>(DateTime.Now, content)); | |
} | |
} | |
public class Client | |
{ | |
private void Run() | |
{ | |
var factory = new MyBusinessObjectFactory(new DummyBusinessRepository()); | |
var myRunnerId = new Guid(); | |
MyBusinessObject myObject = factory.Create(myRunnerId); | |
if(myObject.IsBusinessRequirementMet()) | |
myObject.PerformBusinessLogic(); | |
} | |
} | |
public interface IBusinessRepository | |
{ | |
string GetContent(Guid id); | |
} | |
public class DummyBusinessRepository : IBusinessRepository | |
{ | |
public string GetContent(Guid id) | |
{ | |
return id.ToString(); | |
} | |
} | |
} |
The first class is an actual business object : It’s built from some properties, has some business logic. Its single responsibility is to perform business logic. It shouldn’t embed any infrastructural concern ( like database connection for example)
The second class is the factory itself, that handle the full creation process of our BusinessObject. Its responsibility includes to fetch data from a repository, and to call the business class constructor.
The third class is a simple runner, that instanciate the factory, get the business object from it, and perform what the program is meant to do. Thanks to the Factory Method Pattern, the Runner is not polluted with any construction logic, everything is delegated to the factory object.
2) Increase the system testability:
Obviously, by splitting the responsibilities of your code into different modules, you are, de facto, improving the testablity of your program.
But in some cases, you can use the factory method pattern as a way to use a TestDouble where your usual mocking techniques cannot apply.
For example, when your code is consuming an external object, and that object has no interface, like this NetworkMessage.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace ExternalLibrary | |
{ | |
public class NetworkMessage | |
{ | |
static readonly TimeSpan TimeToLive = TimeSpan.FromSeconds(10); | |
private readonly DateTime _creation; | |
private Status _status; | |
private readonly object _content; | |
public NetworkMessage(Status status, object content) | |
{ | |
_creation = DateTime.UtcNow; | |
_status = status; | |
_content = content; | |
} | |
public bool IsSuccess() | |
{ | |
if (HasTimedOut()) | |
_status = Status.Failed; | |
return _status == Status.Succeeded; | |
} | |
private bool HasTimedOut() | |
{ | |
return (_creation.Add(TimeToLive)) < DateTime.UtcNow; | |
} | |
public T GetContentAs<T>() where T : class | |
{ | |
var castedContent = _content as T; | |
if (castedContent == null) | |
throw new InvalidCastException("contet couldn't be casted into " + typeof(T)); | |
return _content as T; | |
} | |
} | |
public enum Status | |
{ | |
Pending, | |
Succeeded, | |
Failed | |
} | |
public class NetworkService | |
{ | |
public Tuple<int, object> SendMessage() | |
{ | |
// for ske of simplicity, some static data… | |
return new Tuple<int, object>(1, new object()); | |
} | |
} | |
} |
As you can see, the main class relies on DateTime.Now, that make the code relying on it quite complicated to test.
Here is our own NetworkClient, without factory for the NetworkMessage :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ExternalLibrary; | |
namespace Oinant.Blog.Factory.ForTesting | |
{ | |
public class NetworkClientWithoutMessageFactory | |
{ | |
public string SendRequest() | |
{ | |
var message = new NetworkService().SendMessage(); | |
var networkMessage = new NetworkMessage((Status)message.Item1, message.Item2); | |
return networkMessage.IsSuccess().ToString() + " " + networkMessage.GetContentAs<string>(); | |
} | |
} | |
} |
Here, in order to be able to test every execution path of our client, we have to know precisely how the external library behaves internally, and even use some Microsoft.Fakes to create shims of System.DateTime. That’s a lot of test code that is not really relevant, because it’s out of our scope. Futhermore, we just want to control the NetworkMessage output in order to ensure that our network client behaves correctly.
To achieve this, we can add a factory to our client :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ExternalLibrary; | |
namespace Oinant.Blog.Factory.ForTesting | |
{ | |
public class NetworkClientWithMessageFactory | |
{ | |
private readonly INetworkMessageFactory _networkMessageFactory; | |
public NetworkClientWithMessageFactory(INetworkMessageFactory networkMessageFactory) | |
{ | |
_networkMessageFactory = networkMessageFactory; | |
} | |
public string SendRequest() | |
{ | |
var message = new NetworkService().SendMessage(); | |
var networkMessage = _networkMessageFactory.Create((Status)message.Item1, message.Item2); | |
return networkMessage.IsSuccess().ToString() + " " + networkMessage.GetContentAs<string>(); | |
} | |
} | |
public interface INetworkMessageFactory | |
{ | |
NetworkMessage Create(Status status, object content); | |
} | |
public class ConcreteNetworkMessageFactory : INetworkMessageFactory | |
{ | |
public NetworkMessage Create(Status status, object content) | |
{ | |
return new NetworkMessage(status, content); | |
} | |
} | |
} |
And testing becomes really easy, by implementing another factory, that creates an object which inherits from our external object :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ExternalLibrary; | |
using Oinant.Blog.Factory.ForTesting; | |
namespace Factory.Tests | |
{ | |
public class TestFactory : INetworkMessageFactory | |
{ | |
public NetworkMessage Create(Status status, object content) | |
{ | |
var message = new NetworkMessageDouble(status, content); | |
return message; | |
} | |
} | |
class NetworkMessageDouble : NetworkMessage | |
{ | |
private readonly Status _status; | |
private readonly object _content; | |
public NetworkMessageDouble(Status status, object content) : base(status, content) | |
{ | |
_status = status; | |
_content = content; | |
} | |
public new bool IsSuccess() | |
{ | |
return _status == Status.Succeeded; | |
} | |
public T GetContentAs<T>() where T : class | |
{ | |
return _content as T; | |
} | |
} | |
} |
In this article, we saw that the Factory Method pattern helps us respecting the SOLID’s Single Responsibility Principle, and can help us with external/legacy code integration, by providing us a way to enhance testability.
Note : all the code of this article is accessible on this github repository