使用Angular2及WebApi开发SPA类型的企业应用 - Part 5- 依赖注入和控制反转

来源:互联网 发布:教育 大数据 知乎 编辑:程序博客网 时间:2024/06/14 15:11

使用Angular2及WebApi开发SPA类型的企业应用 - Part 5 依赖注入和控制反转
作者:techcoaching,翻译:飘落寒冰
原文 有道
注:第一次翻译文章,有错译之处还请多多包涵,欢迎指出以便改进。

在本文中,我们根据实际情况分析问什么采用或者不用DI&IoC。DI并非不好,每种技术都有优缺点,我们需要了解的是什么时候使用这种技术来更好的为我们的业务服务。

该系列的全部文章

  1. 概览
  2. 添加新角色
  3. 项目结构
  4. 多语言
  5. 依赖注入和控制反转-为什么和为什么不?
  6. RESTful & WebApi
  7. 应用生命周期管理
  8. 应用构建与部署

简介

本示例使用了Ioc&DI,希望有助于大家了解和使用它们。

DI - 依赖注入

DI是一种很有效的设计模式,它帮助我们注入所依赖的对象的引用:

class UserService : IUserService{    private IUserRepository userRepository;    public UserService(IUserRepository userRepository)    {        this.userRepository = userRepository;    }    public void UserRepositoryForSomeActio(){        this.userRepository.<callSomeMethod>();    }}

上面的代码显示出userRepository将会被自动注入,当我们需要使用UserRepositoryForSomeActio方法时,该对象已经被创建好。

这看起来很cool,我们只需关心业务逻辑的方法。

在一些小应用环境中,这样做很棒,而在一些较为复杂的应用中,它又如何呢?(当下的一些企业应用)

企业应用中有大量依赖于其他object的大object。

例如:Order object 依赖于:
- User (who created order)
- Orderline
- Category
- Product
- Promotion
- Unit of Measurement (UOM)
- Branch
- …

OrderService需要注入所有依赖的对象以及相应repository:

class OrderService : IOrderService{    private IUserRepository userRepository;    private IBranchRepository branchRepository;    private IOrderLineRepository orderlineRepository;    private IOrderCategoryRepository orderCategoryRepository;    private IProductRepository productRepository;    private IUOMRepository uomRepository;    public UserService(        IUserRepository userRepository,        IBranchRepository branchRepository,        IOrderLineRepository orderlineRepository,        IOrderCategoryRepository orderCategoryRepository,        IProductRepository productRepository,        IUOMRepository uomRepository,    )    {        this.userRepository = userRepository;        this.branchRepository = branchRepository;        this.orderlineRepository = orderlineRepository;        this.orderCategoryRepository = orderCategoryRepository;        this.productRepository = productRepository;        this.uomRepository = uomRepository;    }    public void UserRepositoryForSomeActio(){        this.userRepository.<callSomeMethod>();    }}

这里有一些需要改进的地方:
- 我们需要定义一些私有变量来存放注入的repository对象(如:private IUOMRepository uomRepository;)
- 构造函数有太多参数
- 构造函数有太多将注入对象赋给私有变量的操作(如:this.userRepository = userRepository;)

下面是课程应用中使用了DI的某个core entity的实际代码:

namespace App.Services.Impl{    public class DistributionListService : IDistributionListService    {        private IDistributionListRepository _distributionListRepository;        private IDistributionPeriodRepository _distributionPeriodRepository;        private IGeoRouteNorpostRepository _geoRouteNorpostRepository;        private IUnaddressedOrderRepository _unaddressedOrderRepository;        private IAddressedOrderSummaryPerRouteRepository _addressedOrderSummaryPerRouteRepository;        private IOrderUnaddressedGeoRouteRepository _orderUnaddressedGeoRouteRepository;        private IUserRepository _userRepository;        private IVehicleRepository _vehicleRepository;        private IGeoRoutePackageRepository _routePackageRepository;        private IGeoRoutePackageRouteRepository _geoRoutePackageRouteRepository;        private IDepartmentRepository _departmentRepository;        private IAddressedOrderItemsDeliveryTimeRepository _addressedOrderItemsDeliveryTimeRepository;        private ISortingTimeRepository _sortingTimeRepository;        private IOrderRepository _orderRepository;        private IDepartmentDistributionPeriodExecutionStatusRepository _distributionPeriodExecutionStatusRepository;        private IDistributionPeriodService _distributionPeriodService;        private IGeoRouteHouseholdService _geoRouteHouseholdService;        public DistributionListService(            IDistributionPeriodService distributionPeriodService,            IGeoRoutePackageRouteRepository geoRoutePackageRouteRepository,            IGeoRouteHouseholdService geoRouteHouseholdService,            IDistributionListRepository distributionListRepository,            IDistributionPeriodRepository distributionPeriodRepository,            IGeoRouteNorpostRepository geoRouteNorpostRepository,            IUnaddressedOrderRepository unaddressedOrderRepository,            IAddressedOrderSummaryPerRouteRepository addressedOrderSummaryPerRouteRepository,            IOrderUnaddressedGeoRouteRepository orderUnaddressedGeoRouteRepository,            IUserRepository userRepository,            IVehicleRepository vehicleRepository,            IGeoRoutePackageRepository geoRoutePackageRepository,            IDepartmentRepository departmentRepository,            IAddressedOrderItemsDeliveryTimeRepository addressedOrderItemsDeliveryTimeRepository,            ISortingTimeRepository sortingTimeRepository,            IDepartmentDistributionPeriodExecutionStatusRepository departmentDistributionPeriodExecutionStatusRepository            )        {            //assign those injected to private variables        }        public void SomeMethod(){            // Use 3 of above repositories        }    }}

service类中某个方法仅仅用到几个注入的对象(大部分是3个左右)。

我们想一下第一次调用上面“DistributionListService”中的“SomeMethod”的执行步骤。
- 系统尝试创建IDistributionListService的实例
- 系统发现此过程依赖于其他15个repository。
- 在构造DistributionListService传递参数时,这些repository会被创建出来。
- 系统调用“SomeMethod”,并使用其中3个对象来实现业务逻辑

再看一遍,我们创建了15个Repository,我们需要注意在这个过程中可能还有其他被依赖到的对象同时被创建出来。

显而易见的是,业务逻辑开始工作前,将会有一个长长的object列表需要被创建。

在DI中,我们可以理实例的生命周期(请检索“IoC”或“控制反转”),例如:单实例对象,瞬时对象等。
1. 单实例对象
- 所有注册为单实例的类型仅仅只被创建一次
- 下一次调用时,只需要从内存中取出该对象即可
在企业应用环境中,在服务器的内存中我们会有大量的类对象,但只有一部分会被经常使用到,这意味着内存被浪费了。

  1. 瞬时对象
    • 所有注册为瞬时对象的类型在被调用时马上创建
      在企业应用环境中,有一些核心object依赖了大量其他对象(如上面的例子),当创建该类型的实例时,也需要将这些依赖的对象全部创建出来,即便将来只会用到部分,这意味着CPU被浪费了。

IoC - 控制反转

由于上面的一些问题,我决定使用Ioc,我们只创建需要用到的相应的repository。

我们将上面的代码做了一些修改:

namespace App.Services.Impl{    public class DistributionListService : IDistributionListService    {        public DistributionListService()        {            //oh yeah, I'm free and can be removed from the class now        }        public void SomeMethod(){            IResitory1 repo1 = IoC.Resolve<IResitory1>();            IResitory2 repo2 = IoC.Resolve<IResitory2>();            IResitory3 repo3 = IoC.Resolve<IResitory3>();            // and use above repositories for logic business        }    }}

在这段代码中,我们可以看出:
- 它看起来更简洁
- 我们可以添加和删除所以来的类型,并且不会影响到其他代码

通过这种方法,我认为我们可以平衡企业应用对服务器内存和CPU的使用。

授权

本文,以及所包含的源码,文件遵循CPOL协议

0 0
原创粉丝点击