Richard Bailey Richard Bailey - 3 months ago 16
C# Question

Correctly structuring abstraction between models and interfaces

I'm not sure about the title of the question, so please excuse if it is incorrect or misleading.

I'm trying to extend the abstraction architecture between the models and the interfaces implemented on them. I'l start off by demonstrating a simple example, then I'll move to something which requires some assistance.

Ok, so I have a person interface with it's corresponding class model:

public interface IPersonModel<T>
where T : ICompany
{
T Company { get; set; }
}

public class PersonModel : IPersonModel<Company>
{
public CompanyModel Company { get; set; }
}

public class CompanyModel : ICompany
{
public string Name { get; set; }
}


So the above code works great, if the model class only has one property which is a complex type. Thus is can easily be used in Manager method:

public interface IPersonManager
{
Task<IEnumerable<IPersonModel<CompanyModel>>> GetPersonData();
}


Which brings me to my actual issue. Let's say the model classes are more complex, like:

public interface IPersonModel<T, T2, T3>
where T : ICompany
where T2 : IDog<BreedModel>
where T3 : ICar
{
T Company { get; set; }
T2 Dog { get; set; }
T3 Car { get; set; }
}


This will result in updating the
PersonModel
class:

public class PersonModel : IPersonModel<Company, Dog, Car>
{
public CompanyModel Company { get; set; }
public DogModel Dog { get; set; }
public CarModel Car { get; set; }
}


And let's not forget about the
Dog
model class:

public class DogModel : IDog<BreedModel>
{
public string Name { get; set; }

public BreedModel Breed { get; set; }
}

public class BreedModel : IBreed
{
public string Attributes { get; set; }

public void GetBreedData()
{
// ...
}
}


Which will result in the manager method being consumed like:

public interface IPersonManager
{
Task<IEnumerable<IPersonModel<CompanyModel, DogModel, CarModel>>> GetPersonData();
}


I would like to know whether there is a better way of doing this. If there are nested complex type properties in the models, it could turn into a very tedious exercise. If the model has 4 or 5 or even 10 complex type properties, it would turn into quite large generic implementations.

Thanks in advance!

Reason for all this trouble, in a nutshell, trying to accomplish the following architecture:

enter image description here

Answer

When I see a generic type, I tend to try to understand them as: this is a className of Ts: for instance List<int>as a list of Foos or IComparable<Foo> as an IComparable of ints, etc.

Would you consider a Person to be a Person of Companies, or a dog, a dog of breeds?

What I'm getting at, is that your type system seems to be unecessarily using generics here. What is wrong with simply using a nongeneric approach?

public interface IPersonModel
{
    ICompany Company { get; set; }
    IDog Dog { get; set; }
    ICar Car { get; set; }
}

public class DogModel: IDog
{
    public string Name { get; set; }
    public IBreed Breed { get; set; }
}

public class BreedModel : IBreed
{
    public string Attributes { get; set; }
    public void GetBreedData()
    {
       // ...
    }
}

public interface IPersonManager
{
    Task<IEnumerable<IPersonModel> GetPersonData();
}

And now your concrete PersonModel class would look like:

public class PersonModel : IPersonModel
{
    public ICompany Company { get; set; }
    public IDog Dog { get; set; }
    public ICar Car { get; set; }
}