I decided to look into the design patterns so
I can write good code. These days I am learning the Factory Pattern. The first
important rule is "Program to an interface and not the
implementation". What does it mean?
We all write code like this:
Student student = new Student();
This is an example of programming to the implementation. This is because
Student is a concreate class and when we type new then we are
actually making an object of the concreate class. This way we are
exposing the concreate class which will make it harder to be changed in the
future.
A better way is to use the abstract class or an interface like
the one shown below:
public
abstract class User
{
public
abstract void Save();
}
And now every concreate class inherits from the
User abstract class.
public class Student : User
{
public override void Save()
{
Console.WriteLine("Save Student");
}
}
And so does the Teacher:
class Teacher : User
{
public override void Save()
{
Console.WriteLine("Save Teacher");
}
}
Now, you can access the Student as well as Teacher in the
following way:
User user = new Student(); // Student is created
User user = new Teacher(); // Teacher is created
This is little better but still we are
using new to create the concreate classes. What we need is some
mechanism that will create these users for us. For this reason let's look into
Simple Factory which will be responsible for creating the users.
Here is our factory defined which is
responsible for creating Users.
public class UserFactory
{
public User CreateUser(string type)
{
if (type.Equals("Student"))
return new Student();
else if (type.Equals("Teacher"))
return new Teacher();
else if (type.Equals("Admin"))
return new Admin();
else return null;
}
}
And we can use the factory with the following code:
UserFactory factory = new UserFactory();
User user = factory.CreateUser("Student"); // Student is created
User2 user2 = factory.CreateUser("Teacher"); // Teacher is created
All is good but in the UserFactory we have
If-Else checks which makes the functionality of the Factory dependent on the
checks and everytime a new user is added we need to add a new if-else. We can
remove all the if-else by using the Activator class funtionality. Check out the
new UserFactory
below:
public class UserFactory
{
public User CreateUser(Type type)
{
return (User)Activator.CreateInstance(type);
}
}
Now, the
above factory does not depends on the if-else checks but it creates and
returns the instance of the object created and return the
interface/abstract
class.
And Here is
how you can use the
new factory.
static void Main(string[] args)
{
UserFactory factory = new UserFactory();
User user = factory.CreateUser(typeof(Student));
user.Save();
user = factory.CreateUser(typeof(Teacher));
user.Save();
}
Abstract
Factory:
If your
factory creates different types of products then you can also make the abstract
factory. The abstract factory will have some abstract methods which will be
implemented in the concreate factories.
Take a look
at the abstract factory below:
public abstract class UserFactory
{
public abstract User CreateUser();
}
And here
are the StudentFactory and TeacherFactory:
class StudentFactory : UserFactory
{
public override User CreateUser()
{
return new Student();
}
}
class TeacherFactory : UserFactory
{
public override User CreateUser()
{
return new Teacher();
}
}
And in the
main program you can use it like this:
static void Main(string[] args)
{
UserFactory factory = new StudentFactory();
User user = factory.CreateUser(); // Student is created
user.Save();
factory = new TeacherFactory();
User user = factory.CreateUser(); // Teacher is created
user.Save();
}
If you
think this can be much improved then please let me know. Maybe a factory using
Generics!!