Question

I am just starting in DDD and have a question regarding interfaces of objects and repositories. Suppose I have the following objects

public interface IPerson { ... }

public class Student 
{
    double gpa;
    ...
}

public class Teacher
{
    double salary; ...
}

then I also have two repositories such as

public class StudentRepository :IRepository { public void Save(Student) }

public class TeacherRepository :IRepository { public void Save(Teacher) }

My question is, suppose I have a list of IPerson objects called persons, is there a way where I can just do something like repository.Save(persons) ? Without having to use reflection to figure out what type the IPerson actually is.

I currently have another class

PersonRepository :IRepository 
{
     public void Save(IPerson person)
     {
          if(Person is Student)
          {
               new StudentRepository.Save(person as Student);
          }
          else if(Person is Teacher)
          { ....}
      }
}

Then I can call personRepository.Save(persons); However this doesnt feel like an optimal way to structure things. How can I improve this design?

Thanks

EDIT:

What I'm looking for is, say I receive an IPerson object called person. I do not necessarily know what implementation it is, I just want to call repository.Save(person) and have it call the correct repository. Is there a way to do this without using some sort of switch statement with reflection?

Was it helpful?

Solution

Consider using generic repository

class Repository<T> :IRepository<T>
{
     public void Save(T entity)
     {
         ...
     }
}

Usage

IRepository<Student> repo1 = new Repository<Student>();
repo1.Save(new Student());

IRepository<Teacher> repo2 = new Repository<Teacher>();
repo2.Save(new Teacher());


Next you can use IoC container and DI just to pass repositories around instead of creating them

At the top level, say in the main method or global.asax

IRepository<Student> studentRepo = IoC.Current.Resolve<IRepository<Student>>();

Later in a class that needs to save data, pass IRepository<Student> studentRepo into constructor

class Foo
{
    private IRepository<Student> repo

    Foo(IRepository<Student> repo)
    {
        this.repo = repo;
    }

    public void Save(Student s)
    {
        repo.Save(s);
    }
}

EDIT

You can move a save operation to the IPerson<T>

class Person<T> : IPerson<T>
{
    private IRepository<T> repo;

    Person(IRepository<T> repo)
    {
        this.repo = repo;
    }

    public void Save()
    {
        repo.Save<T>();
    }
}

So when you derive Teacher and Student from Person<T> you pass correspondent T, like

class Student : Person<Student>
{
    private IRepository<Student> repo;

    Person(IRepository<Student> repo):base(repo)
    {
       ...
    }    
}

This shall give you the ability to work with List without Reflection or switch kung fu.

OTHER TIPS

You can potentially have a method with C# generics

interface Repository<TEntity> where TEntity : class {

    void Save(TEntity entity);    
}

But I would discourage having generic (as in generalized, not C# generics) repositories. Repository interface should be domain driven and specific to your entity. Please consider this article by Greg Young.

It is also not clear why you have interfaces for you entities (IPerson). Interfaces are usually created at the seam of the application. Are you planning to have more than one implementation of IPerson?

Two possible approaches.

First, interfaces specific for domain types

interface IStudentRepository
interface ITeacherRepository
class StudentRepository : IStudentRepository
class TeacherRepository : ITeacherRepository

Second, a generic interface

interface IRepository<T>
class StudentRepository : IRepository<Student>
class TeacherRepository : IRepository<Teacher>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top