The Abstract Factory Design Pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.
Say we are building a school management application for several schools, and a feature we need to build involves listing courses offered to students based on school and department.
Our aim is to list courses offered by a student object based on the department (one factory) and the school (another factory).
First, we create an interface for the student object. Create a Student.cs file and write the code below in it.
namespace AbstractFactoryDesign{public interface IStudent{List<string> Courses();}}
Next, we create the student object of various schools and departments. The two schools we are using are FUTA and UI. I suffixed the class name with the school name to create the distinction
namespace AbstractFactoryDesign{public class BioStudentFuta : IStudent{public List<string> Courses(){return new List<string>{"Bio 101", "Bio 201"};}}public class ChemStudentFuta : IStudent{public List<string> Courses(){return new List<string>{"Chem 101", "Chem 201"};}}public class GeoStudentFuta : IStudent{public List<string> Courses(){return new List<string>{"Geo 101", "Chem 201"};}}public class MedStudentUI : IStudent{public List<string> Courses(){return new List<string>{"SRG 101", "SRG 102"};}}public class MechStudentUI : IStudent{public List<string> Courses(){return new List<string>{"MEE 101", "MEE 102"};}}}
Now, we want to build the school factory.
Think like this, a factory is where products are made. Building a school factory will produce schools.
So, we need to build a factory that produces two schools: UI and FUTA
namespace AbstractFactoryDesign{public abstract class StudentFactory{public abstract IStudent GetStudent(string studentDept);public static StudentFactory CreateStudentFactory(string studentSch){if(studentSch.Equals("UI"))return new UIStudentFactory();elsereturn new FutaStudentFactory();}}}
There are two methods here:
Now that we have written the factory that produces school, we need to write the department factory that produces the students by department.
Here:
public class UIStudentFactory : StudentFactory{public override IStudent GetStudent(string studentDept){if(studentDept.Equals("Med"))return new MedStudentUI();else if(studentDept.Equals("Mech"))return new MechStudentUI();elsereturn null;}}public class FutaStudentFactory : StudentFactory{public override IStudent GetStudent(string studentDept){if(studentDept.Equals("Geo"))return new GeoStudentFuta();else if(studentDept.Equals("Bio"))return new BioStudentFuta();else if(studentDept.Equals("Chem"))return new ChemStudentFuta();elsereturn null;}}
The UIStudentFactory class and the FUTAStudentFactory class both inherit from the abstract StudentFactory Class.
The two classes are both factories that produce the student object based on the studentDept.
It is important to point out that the Abstract Class they both inherited from does not know about them; hence, the term abstract.
Finally, we can consume it on the client.
class Program{static void Main(string[] args){IStudent student = null;StudentFactory studentFactory = null;List<string> courses = null;//create a UI student factory by passing the factory type as UIstudentFactory = StudentFactory.CreateStudentFactory("UI");Console.WriteLine("Student School: "+ studentFactory.GetType().Name);// get bio student by passing the student type.student = studentFactory.GetStudent("Med");Console.WriteLine("Student Dept: "+ student.GetType().Name);courses = student.Courses();foreach (var item in courses){Console.WriteLine("Course code: "+ item);}Console.WriteLine();Console.WriteLine("------------------------------");Console.ReadLine();}}
In the above code we:
And just like that, we have solved a problem without writing a lot of if
statements. In the event that we wanted to add another school, it would be easier to do so.
Always remember to think of Abstract Factory Design Pattern as about building an abstract factory (not concerned with reality) of factories.