문제

I'm creating a class library API that wraps business logic and access to an SQL Server database via Entity Framework 6.

I've designed it using the Unit of work and repository patterns. The purpose is to make it easy to use and to unit test.

Business logic and validation will be performed in the service layer. I will not use an IOC container because I feel that it would complicate the API usage.

The project have 15 repositories and services

The current design is as follows:

Service Layer A -> Unit of work -> Repository A and or B
Service Layer B -> Unit of work -> Repository B and or A...
...

public class ServiceA : IServiceA, IService
{
    private readonly IUnitOfWork unitOfWork;

    public AssetService(IUnitOfWork unitOfWork)
    {
        this.unitOfWork = unitOfWork;
    }

    ...

    public IList<DomainObjectA> GetAll()
    {
        return unitOfWork.RepositoryA.GetAll();
    }

    public void Dispose()
    {
        unitOfWork.Dispose();
    }

    ...
}

public class UnitOfWork : IUnitOfWork
{
    private readonly MyDbContext context = new MyDbContext();
    private IRepositoryA repositoryA;
    private IRepositoryB repositoryB;
    ...

    public IRepositoryA RepositoryA
    {
        get { return repositoryA = repositoryA ?? new RepositoryA(context); }
    }

    public IRepositoryB RepositoryB
    {
        get { return repositoryB = repositoryB ?? new RepositoryB(context); }
    }

    ...

    public void Save()
    {
        context.SaveChanges();
    }

    public void Dispose()
    {
        context.Dispose();
    }
}

public class RepositoryA : Repository, IRepositoryA
{
    public RepositoryA(MyDbContext context)
        : base(context) {}

    public IList<DomainObjectA> GetAll()
    {
        return context.tblA.ToList().Select(x => x.ToDomainObject()).ToList();
    }

    ...
}

Since this is an API that should be used by other projects, I need a nice and "fairly" easy to use interface for the user that consumes the API. Because of this the UnitOfWork is created in this "public interface" between the user and the service layer, see below.

I also think it's best that the using-statement lies within the API so that the db-context is disposed properly and immediately after each service call.

I started out using the Proxy pattern for this: Example:

public class ProxyA : Proxy, IServiceA
{
    public IList<DomainObjectA> GetAll()
    {
        using (var service = GetService<ServiceA>())
            return service.GetAll();
    }
    ...
}

public abstract class Proxy
{
    protected T GetService<T>() where T : IService
    {
       return (T)Activator.CreateInstance(typeof(T), new object[] { new UnitOfWork()});
    }
}

But this would require me to create a proxy for each service. I could of course skip the service interface in the proxy and create a common proxy which handles all the services.

I've also looked at the Facade pattern but can't decide which pattern to use for this particular scenario.

My questions:
Is this a good approach or are there any other design patterns that will solve this problem?

Also, should there be one public API entry point or several, grouped by some business logic?

도움이 되었습니까?

해결책

I see nothing wrong with your design and the patterns you use.

Regarding the proxy pattern it is your call if you want to use it or not. As you mention you have to create boiler plate code to create one for every service. If it is arguable if you want to use it only to hide the call to the db service, or you prefer to add that line of code every time you call the service (and make sure you do it to avoid leaks). Also you may consider if you may need to add extra functionality in the Proxy in the future, which will put extra weight to create the proxy option.

Regarding a single entry point or several, I would create a ServiceA, ServiceB, ServiceC etc (so several) grouped for business logic domains. Typically you'll have between 5-20 (just an approximate number to give an idea of the magnitude)

You may want to review the interface segregation principle which supports this idea

http://en.wikipedia.org/wiki/Interface_segregation_principle

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top