Categories: Design Pattern

Creational Patterns – Factory Method

Factory Method – Provides interface classes for creating objects in the superclass. It allows the superclass changes the object types that will be made.

From Design Pattern – Creational Patterns

Structure

Factory Method class diagram UML

Applicability

  • Using the Factory Method based on when you don’t know the exact type and dependencies object works with your code in the beforehand situation.
  • Using the Factory Method is when you want to provide your library or framework with the method that extends its internal objects.
  • Using the Factory Method is when you want to save one file or system resources and reuse existing objects to replace them every time.

Pros and Cons

PROS

  • Open-close principle.
  • Single Responsibility principle
  • Avoid tight coupling between the creator class and the concrete objects.

CONS

  • This pattern will let the code become complex since you need the subclasses to implement the pattern. The best-using case is when you need this pattern into an existing hierarchy of creator class.

How to Implement

#1 Basic Sample

class Client
{
 private IFactoryMethod<string> repo;

 public Client(IFactoryMethod<string> _repo)
 {
  this.repo = _repo;
 }
 public void Main()
 {
  var o = new ConcreteCreatorA<string>(repo);
  Console.WriteLine(o.SomeOperation());
 }
}


public abstract class Creator<T> where T : class
{
 public abstract IFactoryMethod<T> FactoryMethod();

 public string SomeOperation()
 {
  var product = FactoryMethod();
  var result = "Creator: The same creator's code has just worked with "
   + product.Operation();

  return result;
 }
}

class ConcreteCreatorA<T> : Creator<T> where T : class
{
 private IFactoryMethod<T> repo;
 public ConcreteCreatorA(IFactoryMethod<T> _repo)
 {
  this.repo = _repo;
 }


 public override IFactoryMethod<T> FactoryMethod()
 {
  if (repo == null)
   return new FactoryMethodA<T>();
  else
   return this.repo;
 }
}


public interface IFactoryMethod<T> where T : class
{
 string Operation();
}

public class FactoryMethodA<T> : IFactoryMethod<T> where T : class
{
 private string str;

 public FactoryMethodA(string _str)
 {
  this.str = _str;
 }

 public FactoryMethodA()
 { }

 public string Operation()
 {
  return "{Result of ConcreteProductA}";
 }
}

#2 Web Application Project

Step 1 Create the generic interface class files and two generic repository files about the FactoryMethod. A new generic interface class file name sets “IFactoryMethod” under the Core project. One new generic repository class file name sets “FactoryMethodRepoA.” Another new generic repository class file name sets “FactoryMethodRepoB.” The developers put these generic class files under the Infra project.

Fig 1 IFatcoryMEthod interface class file and generic class file – Solution explorer

Step 2 Add a function in the IFactoryMethod.

public interface IFactoryMethod<T> where T : class
{
 Task<T> GetById(int? id);
}

Step 3 FactoryMethodRepoA and FactoryMethodRepoB inherits the IFactoryMethod interface class file, declare the IGenericTypeRepository interface class by the dependency injection methods. The IFactoryMethod<T>.GetById calls IGenericTypeRepository<T>.GetById function.

Fig 2 FactoryMethodRepoA generic repository file source code
public class FactoryMethodRepoA<T> : IFactoryMethod<T> where T : class
{
 private readonly IGenericTypeRepository<T> repo;

 public FactoryMethodRepoA(IGenericTypeRepository<T> _repo)
 {
  this.repo = _repo;
 }

 public FactoryMethodRepoA()
 { }

 public Task<T> GetById(int? id)
 {
  return id.Value != 0 ? Task.Run(async () => await repo.GetById(id.Value) as T) : null;
 }
}

Note: The FactoryMethodRepoB class file source code is the same as the FactoryMethodRepoA class file source code.

Step 4 Create the new class file which name sets “Creator” under the Core project. The Creator class file declares the IFactoryMethod interface class files, creates a new function in which the name sets “GetByID_Creator.”

Fig 3 Creator class file – Solution explorer
public abstract class Creator<T> where T : class
{
 public abstract IFactoryMethod<T> Repo();

 public Task<T> GetByID_Creator(int id)
 {
  var obj = Repo();
  return Task.Run(() => obj.GetById(id).Result as T);
 }
}

Step 5 Create two concrete class files under the Infra project. One class file name sets “ConcreteA.” Another class file name sets “ConcreteB.” Everyone concrete class file inherits the Creator class file, then creates a way in which the name sets “From_Info,” which descript the concrete information return string variable.

public class ConcreteA<T> : Creator<T> where T : class
{
 private readonly IFactoryMethod<T> repo;

 public ConcreteA(IFactoryMethod<T> _repo)
 {
  this.repo = _repo;
 }

 public override IFactoryMethod<T> Repo()
 {
  if (repo == null)
   return new FactoryMethodRepoA<T>();
  else
   return this.repo;
 }

        public string From_Info() => "From ConcreteB class.";
}

Note: The ConcretB class file source code is the same as the ConcreteA class file source code.

Step 6 Create a new controller file which name sets “FactoryMethodController” under the web project. Create the index view file under the web project’s Views folder.

Fig 4 FactoryMethodController controller file – Solution explorer
public class FactoryMethodController : Controller
{
 private ConcreteA<Enterprise_MVC_Core> concreteA;
 private ConcreteB<Enterprise_MVC_Core> concreteB;

 public FactoryMethodController(IFactoryMethod<Enterprise_MVC_Core> _repo)
 {
  this.concreteA = new ConcreteA<Enterprise_MVC_Core>(_repo);
  this.concreteB = new ConcreteB<Enterprise_MVC_Core>(_repo);
 }

 public IActionResult Index()
 {
  var objA = concreteA.GetByID_Creator(1).Result;
  var objA_From = concreteA.From_Info();
  var objB = concreteB.GetByID_Creator(2).Result;
  var objB_From = concreteB.From_Info();

  ViewData["P_1"] = objA_From.ToString().Trim();
  ViewData["P_2"] = objB_From.ToString().Trim();

  Tuple<IEnumerable<Enterprise_MVC_Core>, IEnumerable<Enterprise_MVC_Core>> tuple_View
    = new Tuple<IEnumerable<Enterprise_MVC_Core>, IEnumerable<Enterprise_MVC_Core>>(
     new List<Enterprise_MVC_Core> { objA },
     new List<Enterprise_MVC_Core> { objB }
    );

  return View(tuple_View);
 }
}

Reference

davidsky69

View Comments

Recent Posts

API Gateway in .NET 5 with Ocelot

What is the API gateway? An API gateway is an API management tool that sits…

3 years ago

.NET 5 application with Onion architecture

The .NET 5 SDK is a kind of milestone in the .NET world. The .NET…

4 years ago

SOLID Principles – Dependency inversion principle

In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software…

4 years ago

SOLID Principles – Interface segregation principle

In the field of software engineering, the interface segregation principle (ISP) states that no code…

4 years ago

SOLID Principles – Liskov substitution principle

Subtype Requirement: Let  be a property provable about objects  of type T. Then  should be true for objects  of type S where S is…

4 years ago

SOLID Principles – Open-closed principle

In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be…

4 years ago