REPR Pattern - For C# Developers

Introduction

Widely adopted patterns like MVC (Model-View-Controller) and CQRS (Command Query Responsibility Segregation) are well-known in software architecture. However, a powerful but lesser-known architectural pattern called REPR (Repository, Entity, Presenter, and Response) can significantly simplify the design of C# applications.

What is the REPR Pattern?

The REPR pattern helps separate concerns in application design, allowing cleaner code and making it easier to maintain. Each component plays a distinct role.

  • Repository: Responsible for data retrieval and persistence.
  • Entity: Represents the domain model.
  • Presenter: Prepares the data from the entity in a way that the view can consume.
  • Response: Encapsulates the result, including the outcome (success or failure) and additional information such as errors.

By isolating responsibilities, the REPR pattern promotes a clear structure, making your code easier to understand and test.

Benefits of REPR Pattern

  • Separation of Concerns: The pattern ensures that each part of your code is responsible for a specific task.
  • Scalability: It allows easy scaling of projects by adding more repositories, presenters, or responses.
  • Maintainability: The code is clean, organized, and easy to maintain.
  • Testability: Unit testing becomes easier since you can isolate each component.

Example. Implementing the REPR Pattern in C#

Step 1. "First, create the console application in Visual Studio."

REPR Pattern

Step 2. Create a class named CustomerRepository.

This is called "Repository" in this example.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace REPRPattern
{
    public interface ICustomerRepository
    {
        Customer GetCustomerById(int id);
    }

    public class CustomerRepository : ICustomerRepository
    {
        private readonly List<Customer> _customers = new List<Customer>
    {
        new Customer { Id = 1, Name = "Ajay Kumar", Email = "[email protected]" },
        new Customer { Id = 2, Name = "Vijay Kumar", Email = "[email protected]" }
    };

        public Customer GetCustomerById(int id)
        {
            return _customers.FirstOrDefault(c => c.Id == id);
        }
    }
}

Step 3. Now, create a class named Customer.

This is called "Entity" in this example.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace REPRPattern
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
    }
}

Step 4. Now, create a class named CustomerPresenter.

This is called "Presenter" in this example.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace REPRPattern
{
    public class CustomerPresenter
    {
        public CustomerResponse Present(Customer customer)
        {
            if (customer == null)
            {
                return new CustomerResponse
                {
                    Success = false,
                    Message = "Customer not found",
                };
            }

            return new CustomerResponse
            {
                Success = true,
                CustomerId = customer.Id,
                Name = customer.Name,
                Email = customer.Email
            };
        }
    }
}

Step 5. Now, create a class named CustomerResponse.

This is called "Response" in this example.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace REPRPattern
{
    public class CustomerResponse
    {
        public bool Success { get; set; }
        public string Message { get; set; }
        public int? CustomerId { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
    }
}

Step 6. Now, come into the Program.cs class.

using REPRPattern;

public class Program
{
    public class CustomerService
    {
        private readonly ICustomerRepository _repository;
        private readonly CustomerPresenter _presenter;

        public CustomerService(ICustomerRepository repository, CustomerPresenter presenter)
        {
            _repository = repository;
            _presenter = presenter;
        }

        public CustomerResponse GetCustomerById(int id)
        {
            var customer = _repository.GetCustomerById(id);
            return _presenter.Present(customer);
        }
    }
    public static void Main(string[] args)
    {
        var repository = new CustomerRepository();
        var presenter = new CustomerPresenter();
        var customerService = new CustomerService(repository, presenter);

        // Fetch customer with ID 1
        var response = customerService.GetCustomerById(1);

        if (response.Success)
        {
            Console.WriteLine($"Customer: {response.Name}, Email: {response.Email}");
        }
        else
        {
            Console.WriteLine(response.Message);
        }
    }
}

Step 7. Now run the project.

Final

In this example, the CustomerService coordinates between the repository and the presenter, calling the appropriate methods and returning the CustomerResponse to the client.

Conclusion

The REPR pattern provides a clean and efficient way to separate concerns in your C# applications, making them more modular and testable. In this guide, we explored the fundamentals of the REPR pattern and provided a step-by-step example to help you implement it in your projects. By using this pattern, you can improve the structure of your code, making it easier to scale and maintain.

Happy coding!


Similar Articles