What you're looking at here is actually not so much to do with the repository pattern, per se, and more to do with "dependency injection," where the outside things on which this class depends are "injected" from without, rather rather than instantiated within (by calling new Repository()
, for example).
This specific example shows "constructor injection," where the dependencies are injected when the object is created. This is handy because you can always know that the object is in a particular state (that it has a repository implementation). You could just as easily use property injection, where you provide a public setter for assigning the repository or other dependency. This forfeits the stated advantage of constructor injection, and is somewhat less clear when examining the code, but an inversion-of-control container can handle the work of instantiating objects and injecting dependencies in the constructor and/or properties.
This fosters proper encapsulation and improves testability substantially.
The fact that you aren't instantiating collaborators within the class is what improves testability (you can isolate the behaviour of a class by injecting stub or mock instances when testing).
The key word here when it comes to the repository pattern is encapsulation. The repository pattern takes all that data access stuff and hides it from the classes consuming the repository. Even though an ORM might be hiding all the actual CRUD work, you're still bound to the ORM implementation. The repository can act as a facade or adapter -- offering an abstract interface for accessing objects.
So, when you take these concepts together, you have a controller class that does not handle data access itself and does not instantiate a repository to handle it. Rather the controller accepts an injected repository, and knows only the interface. What is the benefit? That you can change your data access entirely and never ever touch the controller.
Getting further to your question, the repository is a dependency, and it is being provided in the constructor for the reasons outlined above. If you have a further dependency on a CategoryRepository
, then yes, by all means inject that in the constructor as well.
Alternatively, you can provide factory classes as dependencies -- again classes that implement some factory interface, but instead of the dependency itself, this is a class that knows how to create the dependency. Maybe you want a different IDinnerRepository
for different situations. The factory could accept a parameter and return an implementation according to some logic, and since it will always be an IDinnerRepository
, the controller needs be none the wiser about what that repository is actually doing.