Categories: Design Pattern

Creational Patterns – Abstract Factory

Abstract FactoryProvide the classes or interface classes for creating several classes and objects in the superclass. It allows the superclass to alter the object type or other that will be made.

From Design Pattern – Creational Patterns

Structure

Abstract Factory Class Diagram UML

Applicability

Using the abstract factory that the programs work with other related objects, the developers don’t want the source code to depend on the specific class. Maybe the developers know future extensibility or unknown preparatory that is why the developers use the abstract factory.

The abstract factory provides the interface classes or the abstract classes for creating objects from each subclass. Everyone class must have the responsibility only for a single thing. When the subclasses with multiple object types, maybe the programs must import the different factory methods into a stand-alone factory class.

Pros and Cons

Pros

  • It can ensure the factory objects are compatible with each other.
  • Avoid tight coupling between the client code and the factory code.
  • Single Responsibility Principle.
  • Open-closed principle.

Cons

  • The source code will be more complicated than the original source code and isn’t easy to read because of importing multiple interface classes into a stand-alone class.

How to Implement

#1 Basic Sample

public interface IAbstractFactory<T> where T : class
{
    IAbstractFactoryRepositoryA<T> CreateA(T entity);

    IAbstractFactoryRepositoryB<T> CreateB(T entity);
}

class Repository<T> : IAbstractFactory<T> where T : class
{
    public IAbstractFactoryRepositoryA<T> CreateA(T entity)
    {
        return new AbstractFactoryRepositoryA<T>();
    }

    public IAbstractFactoryRepositoryB<T> CreateB(T entity)
    {
        return new AbstractFactoryRepositoryB<T>();
    }
}

public interface IAbstractFactoryRepositoryA<T> where T:class
{
    bool Create(T entity);
}

public interface IAbstractFactoryRepositoryB<T> where T : class
{
    bool Create(T entity);
}

class AbstractFactoryRepositoryA<T> : IAbstractFactoryRepositoryA<T> where T : class
{

    public bool Create(T entity) => true;
}

class AbstractFactoryRepositoryB<T> : IAbstractFactoryRepositoryB<T> where T : class
{
    public bool Create(T entity) => true;
}

#2 Web Application Project

Step1 Create two interface classes and the generic repository classes. One interface class file name sets “IAbstractFactoryA.” Another interface class file name sets “IAbstractFactoryB.” One generic repository class file name sets “AbstractFactoryA_Repository.” Another interface class file name sets “AbstractFactoryB_Repository.”

Fig 1 Solution Explorer

Step 2 Create CRUD in each repository and the “Get” function about the database connection to check the database connection status. The “Get” function helps the developer to double-check the dependency injection issue.

public class AbstractFactoryA_Repository<T> : IAbstractFactoryA<T> where T : class
{
 private readonly DemoDbContext dbContext;

 public AbstractFactoryA_Repository(DemoDbContext _dbContext)
 {
  this.dbContext = _dbContext;
 }

 public AbstractFactoryA_Repository()
 { }

 public Task<bool> Get()
 {
  if (dbContext != null)
  {
   var o = dbContext.Set<T>().ToList();
   return Task.FromResult(true);
  }
  else
   return Task.FromResult(false);
 }

 public Task<IEnumerable<T>> GetAll()
 {
  try
  {
   var obj = dbContext.Set<T>().ToList() as IEnumerable<T>;
   return Task.FromResult(obj);
  }
  catch (Exception e)
  {
   Debug.WriteLine("Commit Exception Type: {0}", e.GetType());
   Debug.WriteLine("Message: {0}", e.Message);
   return null;
  }
 }

 public Task<T> GetByID(int? id)
 {
  try {
   var obj = dbContext.Set<T>().Find(id.Value) as T;
   return Task.FromResult(obj);
  }
  catch (Exception e)
  {
   Debug.WriteLine("Commit Exception Type: {0}", e.GetType());
   Debug.WriteLine("Message: {0}", e.Message);
   return null;
  }
 }

 public Task Create(T entity)
 {
  try
  {
   dbContext.Set<T>().Add(entity);
   dbContext.SaveChanges();
   return Task.FromResult(true);
  }
  catch (Exception e)
  {
   Debug.WriteLine("Commit Exception Type: {0}", e.GetType());
   Debug.WriteLine("Message: {0}", e.Message);
   return Task.FromResult(false);
  }
 }

 public Task Update(T entity)
 {
  try
  {
   dbContext.Entry(entity).State = EntityState.Modified;
   dbContext.SaveChanges();
   return Task.FromResult(true);
  }
  catch (Exception e)
  {
   Debug.WriteLine("Commit Exception Type: {0}", e.GetType());
   Debug.WriteLine("Message: {0}", e.Message);
   return Task.FromResult(false);
  }
 }

 public Task Delete(T entity)
 {
  try
  {
   dbContext.Entry(entity).State = EntityState.Deleted;
   dbContext.SaveChanges();
   return Task.FromResult(true);
  }
  catch (Exception e)
  {
   Debug.WriteLine("Commit Exception Type: {0}", e.GetType());
   Debug.WriteLine("Message: {0}", e.Message);
   return Task.FromResult(false);
  }
 }
}

Step 3 Create an interface class that describes all of the interface-generic repositories. This interface class file name sets “IAbstractFactory.”

Fig 2 IAbstractFactory source code
public interface IAbstractFactory<T> where T : class
{
 IAbstractFactoryA<T> CreateA();
 IAbstractFactoryB<T> CreateB();
}

Step 4 Create a generic repository for the “IAbstractFactory.” This repository class file name sets “AbstractFactoryRepo.”

Fig 3 Solution explorer – Abstract Factory

Step 6 Statement two interface functions and do the dependency injection about IAbstractFactoryA and IAbstractFactoryB.

Fig 4 AbstractFactoryRepo source code
public class AbstractFactoryRepo<T> : IAbstractFactory<T> where T : class
{
 private readonly IAbstractFactoryA<T> RepoA;
 private readonly IAbstractFactoryB<T> RepoB;

 public AbstractFactoryRepo(
  IAbstractFactoryA<T> _RepoA,
  IAbstractFactoryB<T> _RepoB)
 {
  this.RepoA = _RepoA;
  this.RepoB = _RepoB;
 }

 public IAbstractFactoryA<T> CreateA()
 {
  if (RepoA == null)
   return new AbstractFactoryA_Repository<T>();
  else
   return this.RepoA;
 }

 public IAbstractFactoryB<T> CreateB()
 {
  if (RepoA == null)
   return new AbstractFactoryB_Repository<T>();
  else
   return RepoB;
 }
}

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