If you just started reading this and you know about dependency injection...this is not an argument that factories are better than dependency injection frameworks at all. The only argument that I can come up with that they are better than DI frameworks is that factories are a lot lighter weight and you may save some time not jumping through technical hoops that a DI framework will require.
What is a Constructor?
You may have been expecting at this point that I would start off by detailing what exactly a factory is, but in fact, I can't really explain factories unless I explain what a constructor is. I assume if you are reading this then you must, at some level, understand object oriented programming. If you do not, may I suggest a good book on the subject matter as listed below:Constructors are where we place logic that happens when an object is allocated into memory and where any member variables are initialized.
Dependencies are anything the object needs to complete its intended purpose. A dependency can be a simple variable such as an integer, float, or string that can represent things like file names, account codes, and index keys; or... it can be another object that the object depends on to complete its purpose such as an SDK/API wrapper or a data access layer object. In general, anytime you use the new keyword it should be in the constructors.
However most of the code I have worked on, and for the most part a great majority of the code that I have created over the years, very rarely use constructors for anything. So, if constructors are how we should be handling dependencies why do we hardly ever use them?
You Just Don't Get Dependencies
If you are not doing the majority of your object initiation inside of a constructor then you probably just don't get dependencies. Your code is most likely littered with innocent looking new statements everywhere and I know exactly where they are, they are used exactly before you need them. In fact, most developers don't even have the common courtesy to put them at the beginning of their overly bloated methods.An example application that does not use dependencies:
namespace MyApplication { public class MyClass { public MyClass() { //I hardly ever put anything here... } public void DoSomethingCool() { var appSettings = new Object(); //Code..... //Explain how to use emailSDK... //........ var emailSDK = new Object(); emailSDK.ServerAddress = "..."; emailSDK.UseEncryption = true; emailSDK.Init(); //Code..... string fileName = "C:\\temp\inputFileName"; //Code.... var myObject = new Object(); //Code... emailSDK.Send(...); } } }
The ideal solution is that your dependencies are properties/members of the base class and that your dependencies are initialized inside of your constructor. Sometimes (but very rarely), it makes more sense to initiate objects directly inside a method. However, most of the time it just leads to bad code.
Moving your dependencies to your constructor:
namespace MyApplication { public class MyClass { public MyClass(string fileName) { //This is where I set up my object for use AppSettings = new Object(); //Here is how we setup the email sdk.... var EmailSdk = new Object(); EmailSdk.ServerAddress = "..."; EmailSdk.UseEncryption = true; EmailSdk.Init(); FileName = "C:\\temp\\inputFileName.txt"; } //Its really clear what this class needs in order to do its job.... private string FileName { get; set; } private Object MyObject { get; set; } private Object EmailSdk { get; set; } private Object AppSettings { get; set; } //--------------------------------------------------------------------- public void DoSomethingCool() { EmailSdk.Send(); WriteToFile(FileName); //You get the point } public void DoSomethingElseCool() { EmailSdk.Send(AppSettings.RegionManager); WriteToFile(FileName); } } }
All of the dependency initiation logic that is placed directly at the method level instead of the constructor level are a major cause of method bloat. The second example above really demonstrates how small our methods become when the constructor is used to create objects rather than directly creating them as needed.
The side effect, when you really start to think using dependencies, is that you start solving your problems at the class level rather than the method level. If you do as I suggest in this article, then methods will be small and flexible and you will have more classes in your code then usual. That is, in my experience, a good thing because now you are thinking and writing code at a higher level.
There is much more information regarding dependencies then I care to cover in this article.
Factories Are Way Cooler Than Constructors
As cool as constructors are, factories are way way cooler. Interesting enough, once I started using factories to make better code it really taught me how to use constructors in a more constructive way.Factories are basically constructors that are detached from the class they create. By using factories, a great deal of logic that is usually in the same class can be separated into different classes. Many times objects in your solution will contain similar dependencies. It is much easier to manage these dependencies by putting them into a common class. For instance, all Data Access Components could be using the same connection string.
This concept comes from industrial factories where products are put together at a common building (factory) so that the details of how they are constructed are not needed in order to begin to use the product. For instance, with a laptop you don't have to make the decision of what keyboard to purchase because it was placed/injected into your laptop at the factory and is not an external component like in desktop computers. This makes a laptop a much easier real life object to make use of then a desktop computer. I don't even need to plug it in...I flip up the screen and press the power button and I have a working computer.
In the same way, when I am writing a class suddenly things like file locations, dialog box methods, and application wide settings are just conveniently constructed and ready for me to use.
Factory Methods
Factory members are functions/methods that act as a constructor for an object. They are functions that return a fully functional ready to be used object. You do not necessarily need to put them inside of a special factory class. They can exist in a parent object that is not purely a factory class or it can be put inside of the object that it creates or in any object.public static AccountDataManager CreateAccountDataManager() { var adm = new AccountDataManager(); adm.DataFileName = "Accounts.txt"; return adm; }
Static Factory
Static factories may be the most common implementation of the factory pattern. The advantage of writing a static class with static factory methods, as shown below, is that it is a fairly easy approach and you don't have to think much about how to access the factories. You can simply call them like any other static function anywhere in you code without regard for initiating a new factory object.For small projects this is a good approach because its easy for yourself and for other developers to understand. I also recommend that you become familiar with this approach because it is very common in existing frameworks and code in general. You will find it in both new and older code bases.
Declaring a single factory for the application:
namespace FactoryExample { public static class AppFactory { public static AccountDataManager CreateAccountDataManager() { var adm = new AccountDataManager(); adm.DataFileName = "Accounts.txt"; return adm; } public static ContactDataManager ContactDataManager() { var cdm = new ContactDataManager(); cdm.DataFileName = "Contacts.txt"; return cdm; } } }
Using the factory in your main program:
namespace FactoryExample { class Program { static void Main(string[] args) { var accountManager = AppFactory.CreateAccountDataManager(); var account = new Account() { accountNumber = 23, Balance = 23.23M }; accountManager.Create(account); var contactManager = AppFactory.CreateContactDataManager(); var contact = new Contact() { CustomerId = 12, Name = "John Smith", Email = "jsmith200@yahoo.com" }; contactManager.Create(contact); } } }Most of the time I actually create the main application as a separate class and create it in side of the "program" class using a factory method to create my application as I show below:
Declaring the factory method:
public static FactoryExampleApp CreateApplication() { var app = new FactoryExampleApp(); app.AccountDataManager = CreateAccountDataManager(); app.ContactDataManager = CreateContactDataManager(); return app; }
Usage of the factory:
namespace FactoryExample { class Program { static void Main(string[] args) { var app = AppFactory.CreateApplication(); app.Run(); } } }
Single Factories or Multiple Factories
The above examples, mostly because its easier for me to write an example for, use a single factory for your entire program. I call that factory AppFactory in the above code.Non-Static Factory
It might just be personal preference but I don't like static methods in my code. If I can help it, I will write the factories in non-static class and have them as common properties. The simplest approach, as shown below, will just require an extra new statement when you want to use the factory.Declaring the non static factory:
public class NonStaticAppFactory { public FactoryExampleApp CreateApplication() { var app = new FactoryExampleApp(); app.AccountDataManager = CreateAccountDataManager(); app.ContactDataManager = CreateContactDataManager(); return app; } public AccountDataManager CreateAccountDataManager() { var adm = new AccountDataManager(); adm.DataFileName = "Accounts.txt"; return adm; } public ContactDataManager CreateContactDataManager() { var cdm = new ContactDataManager(); cdm.DataFileName = "Contacts.txt"; return cdm; } }
Simple usage of the factory:
namespace FactoryExample { class Program { static void Main(string[] args) { var app = (new NonStaticAppFactory()).CreateApplication(); } } }
The only thing I will say about static methods are that they are in fact pure evil. So unless you know why they are evil, then you shouldn't use them at all. In fact, what where they thinking when they allowed them in OO languages?
With non-static classes you can also put the factory into a property on the base class and inherit from it when ever you want to access its factory methods.
Factories using a base class:
public class MyBase { public NonStaticAppFactory Factory { get { return new NonStaticAppFactory(); } } } public class MyCoolClass: MyBase { public void DoSomeCoolStuff() { var dataManager = Factory.CreateAccountDataManager(); var account = dataManager.Read(123); var balance = account.Balance; Console.WriteLine(balance); } }
It should be obvious that there are several other ways to declare and use factories. Some would prefer having a single Create method and just pass either a string or Type instance into the method to distinguish what type of object should be created.
Factories are also good for...
- Factories are also good for managing the technique used for creating objects. For instance we might want to return a single object every time the factory method is called (Singleton pattern).
- They can be used to return an interface or purely abstract class instead of a hard object. This is really important because many designers prefer to use abstract classes to hide details instead of private member variables.
When should you not use Factories?
- Your object is going to be used with an existing SDK/API that expects a constructor and does not understand factory methods.
- Heavy usage of factories would violate the conceptual integrity of the software solution. Simply put adding factories to an existing, well written application, that does not use factories could make your code less maintainable because it is not like the rest of the system.
- Usage of factories is not generally accepted by the programming team and using the technique will simply add confusion when others look at your code. A manager or peer some place or somewhere might begin to say “you don't play well with others.”
- Some software systems, for one reason or another, do not lend themselves well to factories. For instance some SDKs, such as the Microsoft .NET DOM library, require child objects to be created by their parent objects. XmlElements must be created using an XmlDocument object. Trying to force the framework into your own factory pattern can prove to be difficult and you may be better off just using the DOM as it was intended instead of adding your own flavor of factories on top of it.
- You have a more elegant dependency injection framework or approach.
- Your program is very small and factories would not really help because there are not that many dependencies to begin with. In this case, I would argue that usage of constructors vs factories is pretty much a wash. If you know how to use factories then it is no more difficult to write factories then it is to write constructors.
- If your solution uses inheritance heavily then factories would be hard to implement everywhere. Instead it could be used for returning higher level objects or for certain parts of your solution.
No comments:
New comments are not allowed.