Question

I have a generic repository pattern, and I'm now seeing that I need a custom method for one specific implementation of this pattern, let's call the implementation CustomerRepository and the method GetNextAvailableCustomerNumber. I have a few ideas but they're not conforming to the SOLID principles of object-oriented design.

I first considered to make a custom repository pattern (ICustomerRepository) for that implementation, but that is not really very feasible. Experience tells me that there has to be some other way which I have not yet considered or even know about at the present time. Besides, I don't think that inventing a new repository interface for every bump in the road should be done so lightly.

I then considered making ICustomerRepository inherit IRepository<Customer> and just add the method signature for GetNextAvailableCustomer, but that goes very much against Liskov's Substitution Principle and I believe it also goes ever so slightly against the Single Responsibility Pattern. I would still be able to implement a customer repository based on IRepository, even though I'd only want to use ICustomerRepository. I would end up with two alternatives and it would no longer be obvious which interface the client should be implementing. I would in this case wish for it only to be possible to implement ICustomerRepository, and not IRepository<Customer>

What would be the proper way to go about this? Is interface inheritance really the way to go, or is there any other preferred method of approach which ideally would conform to LSP?

This is my generic repository interface:

public interface IRepository<T>
    where T : IEntity
{
    T GetById(int id);

    IList<T> GetAll();

    IEnumerable<T> Query(Func<T, bool> filter);

    int Add(T entity);

    void Remove(T entity);

    void Update(T entity);
}
Was it helpful?

Solution

You are actually not breaking Liskov's Substitution Principle. Liskov's says

objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program

In your case you can. With your interpretation of Liskov almost no inheritance and extensions of classes will be allowed.

I think that a ICustomerRepository that "inherents" from IRepository would be just fine. I can still replace ICustomerRepository everywhere where I would use IRepostory (given ICustomerRepository:IRepostory)

Liskov guards against unexpected behavior of subclasses. The most used (although not necessarily the beste) example seems to be the example where a square inherets from a rectangle. Here we have a SetWidth method that is overridden by Square, but Square also sets the height since it is a square. The original methods definition is therefore changed in the subclass and therefore violates the principle.

OTHER TIPS

You will not break the LSP.

Subtypes must be substitutable for their base types. (LSP from Agile.Principles.Patterns.and Practices.In.C#[Robert.C.Martin] book)

If you add a new method GetNextAvailableCustomer to ICustomerRepository, it will still be substitutable by IRepository.

Here is a good article for the repository pattern Entity Framework, Repository and Specification Pattern

source code for different .net versions

Liskov did not mean to extinguish any means to extend a program. The substitution principle is about correctness of the program when you replace a basetype by a subtype.

It is perfectly valid to add additional methods to the subtypes though: Any place where a base type is expected does not know of nor use the additional methods. If you replace the implementation used in those places by a subclass, those places in your code will still work perfectly.

An example of breaking the LSP would be if you create an implementation that throws an exception when you call "Query", or where the "Remove" method adds an element and the "add" method removes an element.

As far as I know creating a ICustomerRepository which inherits from IRepository<Customer> and adds customer specific methods is exactly how the repository pattern was meant.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top