简体   繁体   中英

Why does it seem like this interface provides implementation?

I followed a tutorial and built a back end with EF Core and implemented the Repository Pattern.

First, I created a Repository Interface, and a Repository Base class that provides basic CRUD methods. I then created separate interfaces and repositories for each of my entities for any custom methods I needed to interact with data on these particular classes.

Second, I created an interface and a concrete class called IRepositoryWrapper and RepositoryWrapper. To define the repositories to return and a save method, and then an implementation of retrieving the repositories and the save changes method.

Lastly, I created a controller and injected IRepositoryWrapper into the controller's constructor.

My question is: Why did injecting the interface into the controller actually work? Since the Interface only provides definition, why did the actual implementation seem to come with it? I feel like I should be injecting the concrete class RepositoryWrapper instead.

https://code-maze.com/net-core-web-development-part4/#repository

This works properly, I am just asking an OOP question.

public interface IRepositoryWrapper
{
    IScenarioRepository Scenario { get; }
    IConditionRepository Condition { get; }

    void Save();
}

public class RepositoryWrapper : IRepositoryWrapper
{
    private EvaluatorContext _evaluatorContext;
    private IConditionRepository _condition;
    private IScenarioRepository _scenario;

    public RepositoryWrapper(EvaluatorContext evaluatorContext)
    {
        this._evaluatorContext = evaluatorContext;
    }

    public IScenarioRepository Scenario
    {
        get
        {
            if (_scenario == null)
            {
                _scenario = new ScenarioRepository(_evaluatorContext);
            }

            return _scenario;
        }
    }

    public IConditionRepository Condition
    {
        get
        {
            if (_condition == null)
            {
                _condition = new ConditionRepository(_evaluatorContext);
            }

            return _condition;
        }
    }

    public void Save()
    {
        _evaluatorContext.SaveChanges();
    }
}

Controller Class:


[Route("api/[controller]")]
[ApiController]
public class ScenariosController : ControllerBase
    {

        private IRepositoryWrapper _repositoryWrapper;

        //What I am calling injecting this interface into the constructor
        public ScenariosController(IRepositoryWrapper repositoryWrapper)
        {
            this._repositoryWrapper = repositoryWrapper;
        }

        [HttpGet]
        public IEnumerable<Scenario> FindAll()
        {

            return this._repositoryWrapper.Scenario.FindAllWithIncludes();
        }

    }

Why did injecting the interface into the controller actually work? Since the Interface only provides definition, why did the actual implementation seem to come with it?

The interface defines the signatures, so it can be implemented in any number of ways.

When you pass a class with a concrete implementation to the Controller Constructors Interface argument it knows all the methods are available if the class inherits the interface. This is how it knows what comes with it.

I feel like I should be injecting the concrete class RepositoryWrapper instead.

That's right, when you wire up the DI you hook in the class with the implementation. The Interface argument will accept any class that implements the interface methods.

Why? The main point is seperation of concerns. Using Interfaces allows you to mock implementations and these significantly ease Unit Testing.

They also allow flexibility, say if in USA tax numbers are 11digits and Australia they're 8 digits. Well you could wire up a class with 11digit functionality for USA and 8 digits for Oz. If you didn't have an Interface you could only pass in 11 or 8 - likely forcing you to have two classes that operate the same way with slightly different behaviour. Using Interfaces gives you implementation flexibility.

It's part of the SOLID principles, Interface Segregation Principle: low coupling, and high cohesion and Dependency Inversion Principle: Abstractions should not depend upon details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM