Reputation: 1045
Im new in C#,i have read about constructor,and i have learned the reason we use them is we can assign whatever we want at the time of construct,but something which is difficult for me to understand is,i have a IRepository student like:
public interface IStudentRepository
{
object getAll();
}
i implemented it in StudentRepository:
public class StudentRepository:IStudentRepository
{
public testDBEntities DB = new testDBEntities();
public object getAll()
{
var reslt = (from s in DB.Students
select new StudentViewModel
{
Name = s.Name,
Id=s.Id
});
return reslt;
}
}
in my homeController i can do like the following:
IStudentRepository _repository=new StudentRepository();
public JsonResult Index()
{
var m= _repository.getAll();
return Json(m,JsonRequestBehavior.AllowGet);
}
why should i have a constructor then?like:
IStudentRepository _repository=new StudentRepository();
public HomeController(StudentRepository _repository)
{
this._repository = _repository;
}
public JsonResult Index()
{
var m= _repository.getAll();
return Json(m,JsonRequestBehavior.AllowGet);
}
im sorry if my question is basic but i could not find a right answer,thanks in advance
Upvotes: 3
Views: 3042
Reputation: 4796
Single Responsibility Principle
The first advantage is that your HomeController
doesn't have to worry about creating the StudentRepository
object. Someone else already instanciated it, generated it from a database, a file or user input or whatsoever. And this is great, because your controller can then focus on its real job, not on how to instanciate another object. This is getting closer on the Single Responsibility Principle.
Dependency Injection
Then, to take advantage of the second one, your constructor should receive the interface instead of the class. That is called Dependency Injection.
If later on, for a reason or another, you decide to change your StudentRepository
class in any way, as long as you still implement the interface, you don't have to make a change into your controller.
So your final code could look like :
class HomeController
{
private IStudentRepository _repository;
public HomeController(IStudentRepository _repository)
{
//We don't know who instanciated the repo, but we don't care
this._repository = _repository;
}
public JsonResult Index()
{
//We only know about the repo that it implements IStudentRepository
//So we know we can call this method without a risk.
var m= _repository.getAll();
return Json(m,JsonRequestBehavior.AllowGet);
}
}
When it changes
To illustrate a change, let's say you first want to test your repo, but don't have a proper database connection. So you decide to use a file, there your class would look like :
public class TestStudentRepository : IStudentRepository
{
private string MyDatabaseFilePath;
public object getAll()
{
//Load everything from my text file
}
}
Okay this will work. Let's now say that you have a connection to your database, but that connection requires some steps before being able to use the getAll() method. With your solution, you would have to perform the init steps in your HomeController
.
Now with this pattern, you can do :
public class StudentRepository : IStudentRepository
{
private string _connectionString;
public DatabaseStudentRepository(string ConnectionString)
{
_connectionString = ConnectionString;
}
public object getAll()
{
//Load everything from my text file
}
}
Then, it is the role of the object that is using the controller to make sure it instanciated your object correctly. No changes in your controller.
The factory pattern
Final step is to create a Factory for your StudentRepository. It is the role of the Factory to instanciate a proper repo:
public static class StudentRepositoryFactory
{
public static IStudentRepository InstanciateRepo(bool FromDatabase)
{
if (FromDatabase)
{
return new DatabaseStudentFactory("ConnectionString To my server");
}
else
{
return new TestStudentRepository();
}
}
}
And now, whatever the way you need to init your repo, it is the role of the Factory to do so; while it is the role of the Controller to use one method of your repository, getAll().
Upvotes: 6
Reputation: 7204
I think your constructor isn't correct. It must like
IStudentRepository _repository
public HomeController(IStudentRepository _repository)
{
this._repository = _repository;
}
In fact, it's better to pass the IStudentRepository
in the constructor for respecting the pattern dependency injection
.
Imaging that you want to test your controller by the unit test. So you want to create fake data. If you create new StudentRepository
inside the controller, how to test it?.
But if you pass by the constructor, like :
public class FakeStudentRepository : IStudentRepository
{
//return fake data
}
By some config, the 3rd library ``dependency injection` will pass your fake repo to the controller and you can test it
Upvotes: 1