IoC在复杂服务层的最佳实践

本文关键字:最佳 复杂 服务 IoC | 更新日期: 2023-09-27 18:27:36

我正在开发一个MVC应用程序,我正在使用Unity for IoC。我的应用程序基本上由UI层、服务层和存储库层组成。

我的典型控制器是:

public class TestController : Controller
    {
        private ITestService testServ;
        public TestController(ITestService _testServ)
        {
            testServ= _testServ;
        }
    public ActionResult Index()
    {
        testServ.DoSomething();
        return View();
    }
}

没有什么特别的,我的每个控制器都注入了一个服务对象。因此,我的服务层对象执行复杂的业务规则,聚合来自许多不同存储库的信息。通过使用IoC,我发现我的构造函数看起来过于复杂,但由于该服务需要访问许多存储库,我看不到任何解决方法。

我的服务层中的一个典型类看起来像:

public class TestService : ITestService
    {
        private ITransactionRepository transRepo;
        private IAccountRepository accountRepo;
        private ISystemsRepository sysRepo;
        private IScheduleRepository schRepo;
        private IProfileRepository profileRepo;
        public TestService(ITransactionRepository _transRepo;
                           IAccountRepository _accountRepo;
                           ISystemsRepository _sysRepo;
                           IScheduleRepository _schRepo;
                           IProfileRepository _profileRepo)
        {
            transRepo = _transRepo;
            accountRepo = _accountRepo;
            sysRepo = _sysRepo;
            schRepo = _schRepo;
            profileRepo = _profileRepo;
        }
        public DoSomething()
        {
            //Implement Business Logix
        }
    }

我的一些服务层对象需要10个或更多的存储库。我的存储库使用实体框架,其中每个存储库类在底层数据存储中公开一个表。

在这种情况下,我正在寻求一些关于最佳实践的建议。

IoC在复杂服务层的最佳实践

您已经创建了一个服务层,使其充当底层存储库的门面。这种方法是一种很好的做法,可以为客户端提供粗糙的API。客户端不必担心底层存储库。

由于DI的工作方式,服务本身现在有一个复杂的构造函数。另一种方法是在服务层使用抽象的工厂模式,并进行setter注入。这种建立存储库的复杂性被转移到一个单独的类中,一个自己的工厂。例如:

您可以如下设置测试服务的存储库,而不是构造函数

public class TestService : ITestService
{
    private ITransactionRepository transRepo = DataAccess.transRepo;
    private IAccountRepository accountRepo = DataAccess.accountRepo;
    private ISystemsRepository sysRepo = DataAccess.sysRepo;
    private IScheduleRepository schRepo = DataAccess.schRepo ;
    private IProfileRepository profileRepo = DataAccess.profileRepo;
}

以下是工厂的接口示例

public interface IRepoFactory
{
    ITransactionRepository TransRepo {get;}
    IAccountRepository AccountRepo {get;}
    ISystemsRepository SysRepo {get;}
    IScheduleRepository SchRepo {get;}
    IProfileRepository ProfileRepo {get;}
}

下面是一个混凝土工厂的例子,它将新建所有的存储库。

public class EfFactory : IRepoFactory
{
    public ITransactionRepositry TransRepo { return new TransactionRepository();}
    public IAccountRepository AccountRepo {return new AccountRepository();}
    public ISystemsRepository SysRepo {return new SystemRepository();}
    public IScheduleRepository SchRepo {return new SchRepository();}
    public IProfileRepository ProfileRepo {return new ProfileRepository();}
}

以下是返回混凝土工厂的工厂方法(在您的情况下,它将是EF工厂)

public class RepoFactories
{
    public static IRepoFactory GetFactory(string typeOfFactory)
    {
        return (IRepoFactory)Activator.CreateInstance(Type.GetTypetypeOfFactory)
    }
}

抽象工厂用静态方法新建并返回存储库对象

//示例:factoryName=MyProject.Data.EFFactory(这可以添加到web.config或app.config中)

Public static class DataAccess
{
    private static readonly string DbfactoryName=   ConfigurationManager.AppSettings.Get("factoryName");
    private static readonly IRepoFactory factory = RepoFactories.GetFactory(DbfactoryName);
    public static ITransactionRepositry transRepo
    {
        get {return factory.TransRepo;}
    }
    public static IAccountRepository accountRepo
    {
        get {return factory.AccountRepo;}
    }
}

以下是一些简化(和减少)依赖关系的步骤:

  1. 将您的服务拆分为单独的服务,并将它们注入控制器中。这将减少服务的依赖性数量。不利的一面是,您需要向控制器注入更多的依赖项。下一步是在控制器变得复杂时拆分控制器。记住"单一责任原则"。

  2. 看看Bounded Context模式:您可以尝试将经常出现在单个上下文中的实体分组,并将该上下文注入服务,而不是注入数十个存储库:

    public class TestService : ITestService
    {
        private readonly ITestData testData; // represents a bounded context
        public TestService(ITestData testData)
        {
            this.testData = testData;
        }
        public void DoSomething()
        {
            this.testData.Transactions.Add(...); //It gives you access to Transactions repository
        }
    }