Handling generic and specific implementation

  softwareengineering

Normally we have some code that is common for many (if not all) derived classes. An example would be a generic repository (where I could have a generic Add, Remove, Count, Max, Load etc, or a generic model (example, a common business rule to get a unique value for a new entity based on property type, or a generic save method, etc).

Now, if I were to make a Generic model that accepts Generic repository, it could look ilke:

GenericModel<TEntity> : IGenericModel<TEntity>
{
    internal GenericModel(IRepository<TEntity> genericRepository)
    {

    }
    protected IRepository<TEntity> Repository {get; }
}

Now I need a specific model with a specific repository:

class ActivityModel : GenericModel<Activity>
{
    protected ActivityModel(IActivityRepository activityRepository)
}

where

class ActivityRepository : GenericRepository<Activity>, IActivityRepository { }

That means that in ActivityModel I need to cast Repository property to IActivityRepository anytime I need to use IActivityRepository specific methods, or I can declare a new property in ActivityModel

private new IActivityRepository Repository {get { return base.Repository; } }

to hide the base.Repository property, but I am not sure whether I am doing something wrong by using this approach.

Another approach would be to add another generic paramteter

class GenericModel<TEntity, TRepository> where TRepository : IRepository<TEntity>

but I am not sure if this is also a correct approach.

So any thoughts on how to handle generic and specific implementations?

4

It’s a general aspect of inheritance that you can’t remove stuff.

In your specific example you could just ignore the protected repository, but it would potentially break further inheritance, or at least confuse it.

A simple solution would be just not to inherit from GenericModel at all, but I suppose we can assume GenericModel has some other public functionality that you do want to use.

The general answer is to: ‘Prefer composition over inheritance’, avoid the GenericModel completely and have a private IRepository where required. Then you can simply switch out to a specific repository in classes that use it.

eg:

public class ActivityModel : IGenericFunctionality
{
    public ActivityModel(
        IActivityRepository activityRepository,
        IGenericFunctionalityProvider gfp
    )
    {
        this.gfp = gfp;
        this.activityRepository = activityRepository;
    }

    public void GenericFunctionality() 
    {
        this.gfp.GenericFunctionality();
    }
}

1

LEAVE A COMMENT