第3章:管理组件之间的依赖关系

基于Prism库的复合应用程序可能包含许多松耦合的类型和服务。他们需要提供内容和接收基于用户行为的通知。因为他们是松散耦合的,他们需要一种方式进行互动和相互沟通来提供所需的业务功能。

为了集中这些不同的块,基于Prism库的应用程序依赖于依赖注入容器。依赖注入容器通过提供设施去实例化类的实例和管理他们基于容器配置的寿命来减少对象之间的依赖耦合。在对象的创建过程中,容器注入对象需要的任何依赖。如果那些依赖尚未创建,容器首先创建和解析他们的依赖关系。在某些情况下,容器本身是作为一个依赖被解析。例如,使用Unity Application Block(Unity)作为容器,容器注入模块,所以他们可以在容器中注册他们的View和服务。

下面是使用容器的一些有利之处:

  1. 容器移除对组件的需要以致可以找到它的依赖或管理他们的寿命。
  2. 容器在不影响组建的情况下,允许实现依赖的交换。
  3. 容器允许模拟依赖以致有利于可测性。
  4. 容器允许新的组件被容易地添加到系统中以致增加可维护性。

在基于Prism库的应用程序中,容器有特定的优势:

  1. 当模块被加载时,容器予其注入模块依赖。
  2. 容器被用于注册和解析View models 和 views
  3. 容器可以穿件view models 和 注入 view。
  4. 容器注入组件服务,比如说区域管理和事件集合
  5. 容器用于注册具有特定模块功能的特定模块服务,

          NotePrism指导中的一些样品依靠Unity Application BlockUnity)作为容器。其他代码案例,例如Modularity QuickStarts,使用Managed Extensibility Framework   (MEF)。Prism库本身不是特定的容器,你可以在其他容器中使用它的服务与模式,如Castle WindsorStructureMapSpring.NET

关键的抉择:选择一个依赖注入容器

Prism库为依赖注入容器提供了两个选择:Unity或MEF。Prism是可扩展的,从而允许其他容器被用来代替一点点工作。Unity和MEF都为依赖注入提供相同的基本功能,尽管他们非常不同。由两个容器提供的一些功能包括以下:

  1. 它们两个都在容器中注册类型。
  2. 它们两个都在容器中注册实例。
  3. 它们两个都需要创建注册类型的实例。
  4. 它们都注入注册型实例到构造函数。
  5. 它们都注入注册型实例到属性。
  6. 它们都有为标记类型和需要管理的依赖关系声明属性。
  7. 它们都解析一个对象图的依赖关系

Unity具有的而MEF所不具有的一些功能:

  1. 它解析没有注册的具体类型。
  2. 它解析开放泛型。
  3. 它采用侦听去捕获调用对象并且向目标对象添加额外的功能。

MEF具有的而Unity所不具有的一些功能:

  1. 它在一个目录中发现组件。
  2. 它使用XAP文件下载和组件发现。
  3. 它将属性和集合作为一种新类型的发现。
  4. 它自动导出派生类型。
  5. 它被部署在.NET Framework下。

容器间的能力是不同的,工作也是不同的,但Prism库配合任何容器的工作并且提供类似的功能。当考虑使用哪种容器,记住前面提到的能力,确定适合您的更好的方案。

考虑使用容器

在使用容器之前,你应该考虑下列所述:

  1. 考虑使用容器的时候是否它适合用来注册和解析组件。

(1) 考虑在容器中注册和用容器解析实例对性能的影响是否可以接受。

(2) 如果有许多或深层次的依赖,创造的成本会显著增加。

(3) 如果组件没有任何依赖或不依赖其他类型,没。

(4) 如果组件有单一的对型积分和永远不变的一套依赖关系,必要把它放在容器里。

2. 考虑一个组件的寿命是否应注册为一个单例或实例

(1) 如果组件是一个全局的作为一个单一资源的资源管理器的服务,如日志服务,你可能想将它注册成为单例。

(2) 如果组件向多个消费者提供共享状态,你可能想将它注册成为单例。

(3) 如果每次正在被注入的对象需要有一个它注入过的新实例,也就是依赖对象所需要的那个,那么将其注册为非单例。例如,每个视图可能需要一个视图模型的一个新实例。

3. 考虑你是否想通过代码或配置去配置容器:

(1) 如果你想集中管理所有不同的服务,那就通过配置来配置容器。

(2) 如果你想有条件的注册特定的服务,那就通过代码配置容器。

(3) 如果你具有模块级的服务,考虑通过代码来配置容器,以至于那些服务只有在被加载的时候才会被注册

Note:一些容器,比如MEF,不能通过配置文件来配置,必须通过代码来配置。

 

核心方案

容器被用于两个主要目的----注册和解析

注册

在你将依赖项注入到一个对象之前,依赖关系的类型必须在容器中注册。注册类型通常是通过容器接口和具体实现该接口的类型。主要有两种类型和对象注册的方式:通过代码或通过配置。具体的根据容器的不同而不同。

典型的,在容器中有两种方式通过代码注册类型与对象:

1.你可以用容器注册一个类型或映射,在适当的时候,容器将建立你指定类型的一个实例。

2.在容器中,你可以注册一个现有的对象实例作为一个单例,容器将返回该对象的引用。

Unity容器注册类型

在初始化过程中,一个类型可以被注册为其他类型,比如视图和服务。注册允许他们的依赖性属性通过容器被提供,并且允许他们被其他类型访问。为了达到这个,类型需要有一个容器注入到模块构造函数。下列代码展示在Commanding QuickStart中的OrderModule类型注册了一个类型。

1 public class OrderModule : IModule
2 { 3 public void Initialize() 4  { 5 this.container.RegisterType<IOrdersRepository, OrdersRepository>(new ContainerControlledLifetimeManager()); 6  ... 7  } 8  ... 9 }

      Note:和配置相比,在代码中注册的有利之处在于,只有模块被加载的时候注册才会发生。

 

用MEF来注册类型

为了使用容器注册类型,MEF使用基于属性的系统。自然而然,添加类型注册到容器是很简单的:它需要附加【Export】属性到类型中,如下所示:

1 [Export(typeof(ILoggerFacade))]
2 public class CallbackLogger: ILoggerFacade 3 { 4 }

当使用MEF时的另一个选择是创建一个类的实例并且用容器注册该特定实例。在Modularity for Silverlight with MEF QuickStart 中的QuickStartBootstrapper展示了一个用ConfigureContainer方法的例子

protected   override void ConfigureContainer(){base.ConfigureContainer(); // Because we created the CallbackLogger and it needs to // be used immediately, we compose it to satisfy any imports it has. this.Container.ComposeExportedValue<CallbackLogger>(this.callbackLogger); }

解析

类型被注册之后,它可以作为一个依赖属性被解析或者注入。当一个类型已被解析,容器需要去创建一个新的实例,并注入依赖性属性到这些实例中。

通常而言,当一个类型被解析,会发生下列三件事之一:

  1. 如果类型没有被注册容器会抛出一个异常。

      Note:包括Unity在内的一些容器允许解析一个具体的尚未被注册的类型。

2.如果类型被注册为一个单例,容器将返回单例的实例。如果类型被第一次调用,容器会创建它并为将来的调用一直保留。

3.如果类型没有被注册为一个单例,容器将返回一个新的实例。

       Note默认情况下,用MEF注册的类型是单例并且容器保留对象的引用。在Unity中,新的对象实例在默认情况下返回,容器不保留对该对象的引用。

 

用Unity解析实例

来自Commanding QuickStart的下列代码事例展示了 OrdersEditorViewOrdersToolBar 视图从容器关联他们到相应的区域处被解析。

 1 public class OrderModule : IModule
 2
 3 {  4  5 public void Initialize()  6  7  {  8  9 this.container.RegisterType<IOrdersRepository, OrdersRepository>(new ContainerControlledLifetimeManager()); 10 11 12 13 // Show the Orders Editor view in the shell's main region. 14 15 this.regionManager.RegisterViewWithRegion("MainRegion", 16 17 () => this.container.Resolve<OrdersEditorView>()); 18 19 20 21 // Show the Orders Toolbar view in the shell's toolbar region. 22 23 this.regionManager.RegisterViewWithRegion("GlobalCommandsRegion", 24 25 () => this.container.Resolve<OrdersToolBar>()); 26 27  } 28 29  ... 30 31 }

      OrdersEditorPresentationModel 构造函数包含下列依赖属性,当它被解析时,依赖性属性被注入。

 1 public OrdersEditorPresentationModel( IOrdersRepository   ordersRepository, OrdersCommandProxy commandProxy )
 2
 3 {  4  5 this.ordersRepository = ordersRepository;  6  7 this.commandProxy = commandProxy;  8  9 10 11 // Create dummy order data. 12 13 this.PopulateOrders(); 14 15 16 17 // Initialize a CollectionView for the underlying Orders collection. 18 19 #if SILVERLIGHT 20 21 this.Orders = new PagedCollectionView( _orders ); 22 23 #else 24 25 this.Orders = new ListCollectionView( _orders ); 26 27 #endif 28 29 // Track the current selection. 30 31 this.Orders.CurrentChanged += SelectedOrderChanged; 32 33 this.Orders.MoveCurrentTo(null); 34 35 }

除了在前面的代码显示的构造函数注入,Unity也允许属性注入。当对象被解析时,任何具有【依赖】性质的属性都是被自动解析并注入。

用MEF解析实例

下面的代码示例演示在Modularity forSilverlight with MEF QuickStart中引导程序如何获得外壳的一个实例。代码可以请求接口的实例,而不是请求一个具体类型.

1 protected override DependencyObject CreateShell()
2
3 { 4 5 return this.Container.GetExportedValue<Shell>(); 6 7 }

在任何由MEF解析的类中,你也可以使用构造函数注入,如下面的来自ModuleA in the Modularity for Silverlight with MEF QuickStart的代码示例所示,其中有一个ILoggerFacadeIModuleTracker注入。

 1 [ImportingConstructor]
 2
 3 public ModuleA(ILoggerFacade logger, IModuleTracker moduleTracker)  4  5 {  6  7 if (logger == null)  8  9  { 10 11 throw new ArgumentNullException("logger"); 12 13  } 14 15 if (moduleTracker == null) 16 17  { 18 19 throw new ArgumentNullException("moduleTracker"); 20 21  } 22 23 this.logger = logger; 24 25 this.moduleTracker = moduleTracker; 26 27 this.moduleTracker.RecordModuleConstructed(WellKnownModuleNames.ModuleA); 28 29 }

 

另外一个功能就是依赖注入,正如在ModuleTracker类(来自Modularity for Silverlight with MEF QuickStart)中所示,这个类存在一个ILoggerFacade注入的实例.

 1 [Export(typeof(IModuleTracker))]
 2
 3 public class ModuleTracker : IModuleTracker  4  5 {  6  7 // Due to Silverlight/MEF restrictions, this must be public.  8  9 [Import] public ILoggerFacade Logger; 10 11 }

       Note:在Silverlight中,导入属性和域必须是public.

 

Prism,使用依赖注入容器和服务

通常被称为是“容器”的依赖注入容器,是用来满足组件之间的依赖关系. 满足这些依赖关系通常涉及到的注册和解析.Prism为Unity容器和MEF提供支持,但不是特定容器. 由于库通过IServiceLocator接口访问容器,所以容器可以被取代。要做到这一点,你的容器必须实现IServiceLocator接口。通常,如果要更换容器,您还需要提供你自己的特定容器的引导程序. IServiceLocator接口被定义在Common Service Locator Library中。这是开源的并提供一个抽象 IoC(控制反转)的容器,如依赖注入容器,和服务定位器。使用这个库的目的是在未绑到一个特定的实现的情况下,利用IoC和服务定位。

Prism库提供的UnityServiceLocatorAdapter和MefServiceLocatorAdapter。两个适配器通过扩展ServiceLocatorimplBase类型实现ISeviceLocator接口。下面的插图显示了类层次。

The Common Service Locator implementations in Prism

虽然Prism库不参考或依赖于一个特定的容器,对于应用程序依赖于一个特定的容器却是典型的。这意味着,对于依赖于容器的一个具体应用是合理的,但Prism库不是直接依赖容器。例如,股票交易日数的快速入门包括棱镜依靠统一为容器。其他样品和快速入门依赖MEF。包括Prism在内的the Stock Trader RI and several of the QuickStarts 依赖于Unity作为容器. 其他的例子的QuickStarts依赖于MEF.

IServiceLocator

下列代码展示了IServiceLocator接口

 1 public interface IServiceLocator : IServiceProvider
 2
 3 {  4  5 object GetInstance(Type serviceType);  6  7 object GetInstance(Type serviceType, string key);  8  9 IEnumerable<object> GetAllInstances(Type serviceType); 10 11 TService GetInstance<TService>(); 12 13 TService GetInstance<TService>(string key); 14 15 IEnumerable<TService> GetAllInstances<TService>(); 16 17 }

服务定位器是用下面的代码所示的扩展方法在Prism中被扩展的。你可以看到,IServiceLocator只用于解析,这意味着它是用来获取一个实例而不用于注册。

 1 public   static class ServiceLocatorExtensions
 2  3 {  4  5 public static object TryResolve(this IServiceLocator locator, Type type)  6  7  {  8  9 try 10 11  { 12 13 return locator.GetInstance(type); 14 15  } 16 17 catch (ActivationException) 18 19  { 20 21 return null; 22 23  } 24 25  } 26 27 28 29 public static T TryResolve<T>(this IServiceLocator locator) where T: class 30 31  { 32 33 return locator.TryResolve(typeof(T)) as T; 34 35  } 36 37 }

TryResolve扩展方法-----Unity容器不支持----返回类型的一个实例,该类型如果没有被注册,将会被解析;否则返回null。
      在模块加载时, ModuleInitializer使用 IServiceLocator来解析模块,如下面的代码示例所示。

 1 IModule   moduleInstance = null;
 2
 3 try  4  5 {  6  7 moduleInstance = this.CreateModule(moduleInfo);  8  9  moduleInstance.Initialize(); 10 11 } 12 13 ...

 1 protected virtual IModule CreateModule(string   typeName)
 2  3 {  4  5 Type moduleType = Type.GetType(typeName);  6  7 if (moduleType == null)  8  9  { 10 11 throw new ModuleInitializeException(string.Format(CultureInfo.CurrentCulture, Properties.Resources.FailedToGetType, typeName)); 12 13  } 14 15 16 17 return (IModule)this.serviceLocator.GetInstance(moduleType); 18 19 }

考虑使用IServiceLocator

      IServiceLocator并不意味着是通用的容器。容器的使用具有不同的语义,这往往使决定为什么那个容器被选择。因此,Stock Trader RI直接使用Unity而不是使用IServiceLocator。这是为你的应用程序的开发所推荐的方法。

在下列解决方法中,使用IServiceLocator或许是合适的:

  1. 你是一个独立软件供应商(ISV),设计需要支持多个容器第三方服务.
  2. 你正在设计一个被应用于组织的服务,这个组织使用多容器.

More Infomation

与容器相关的信息,如下所示:

  • "Unity Application  Block" on MSDN:      http://www.msdn.com/unity
  • Unity community site on  CodePlex:      http://www.codeplex.com/unity
  • "Managed Extensibility Framework Overview" on MSDN:      http://msdn.microsoft.com/en-us/library/dd460648.aspx
  • MEF community site on CodePlex:      http://mef.codeplex.com/
  • "Inversion of Control containers and the Dependency Injection pattern" on Martin Fowler's  website:      http://www.martinfowler.com/articles/injection.html
  • "Design Patterns: Dependency Injection" in MSDN Magazine:      http://msdn.microsoft.com/en-us/magazine/cc163739.aspx
  • "Loosen Up: Tame Your  Software Dependencies for More Flexible Apps" in MSDN Magazine:      http://msdn.microsoft.com/en-us/magazine/cc337885.aspx
  • Castle Project:      http://www.castleproject.org/container/index.html
  • StructureMap:      http://structuremap.sourceforge.net/Default.htm
  • Spring.NET:      http://www.springframework.net/

转载于:https://www.cnblogs.com/changbaishan/p/4456384.html

Prism 文档 第三章 管理组件之间的依赖关系相关推荐

  1. Ext JS 6学习文档-第3章-基础组件

    Ext JS 6学习文档-第3章-基础组件 基础组件 在本章中,你将学习到一些 Ext JS 基础组件的使用.同时我们会结合所学创建一个小项目.这一章我们将学习以下知识点: 熟悉基本的组件 – 按钮, ...

  2. Ext JS 6学习文档-第6章-高级组件

    Ext JS 6学习文档-第6章-高级组件 高级组件 本章涵盖了高级组件,比如 tree 和 data view.它将为读者呈现一个示例项目为 图片浏览器,它使用 tree 和 data view 组 ...

  3. ContextCapture User Guide V4.4.11 ContextCapture(Smart3D 帮助文档 第三章 认识软件)

    一.准则 ContextCapture使用一组取自不同视点的静态数码照片作为输入数据. 可以提供各种不同的额外数据:相机属性(焦距.传感器尺寸.主点.镜头失真),照片位置(GPS).照片旋转(INS) ...

  4. ovirt官方安装文档 第三章

    第3章:安装oVirt 安装oVirt引擎包 在您可以配置和使用oVirt引擎之前,您必须安装 rhevm 包和依赖关系. 安装oVirt引擎包 在开始安装oVirt之前,添加官方仓库: # yum ...

  5. ASP.NET Core 中文文档 第三章 原理(5)错误处理

    原文:Error Handling 作者:Steve Smith 翻译:谢炀(Kiler) 校对:高嵩(jack2gs).何镇汐 当你的ASP.NET应用发生错误的时候, 你可以采用本文所述的各种方法 ...

  6. ASP.NET Core 中文文档 第三章 原理(3)静态文件处理

    原文:Working with Static Files 作者:Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay).孟帅洋(书缘) 静态文 ...

  7. Bootstrap学习文档(三)

    Bootstrap 注意下面的组件,很多是需要用到 js 的,所以要引入 Bootstrap 的 js 文件和 jquery 文件在示例代码中,我只是没有写,注意加上哦. 字体图标 Bootstrap ...

  8. (上)vuepress编写API文档verdaccio搭建并发布组件库

    vuepress编写API文档 介绍 搭建 安装 初始化 配置 组件API文档 发布组件库 坑 没有高亮 介绍 想要搭建一个类似elementUI的组件库及相关的API文档,可以直接引用组件,还有代码 ...

  9. c语言槟编程把两个数交换,第三章管理信息系统技术基础.doc

    PAGE PAGE 1 第三章管理信息系统技术基础 管理信息系统是基于管理和计算机的系统,同时也是基于网络的系统.管理信息系统的技术基础主要包括计算机系统.网络技术.数据库技术和科学管理等几个方面的内 ...

最新文章

  1. (转)mxArray数据类型
  2. setcookie无效
  3. 46:八进制到十进制
  4. [YTU]_2625( 构造函数和析构函数)
  5. 006_Spring Data JPA基于方法名称命名规则查询
  6. 批次管理相关事务代码
  7. 列表视图案例2——显示用户列表
  8. ArcGIS JS API 4 —— GET https://static.arcgis.com/fonts/simsun-regular/37888-38143.pbf 404
  9. DNS分别在什么情况下使用UDP和TCP?
  10. 【转载】 C#中使用Sum方法对List集合进行求和操作
  11. paip.Adblock屏蔽onlinedown华军软件园的4秒下载广告总结..
  12. VMware下linux ubuntu 虚拟机复制粘贴-宿主机
  13. Word2010页眉添加两条横线
  14. Python | OpenCV简单生成调色板
  15. DHTMLX Diagram JavaScript/HTML5 Pro Library:5.0
  16. 中药治疗糖尿病十六则常用方-中药治疗糖尿病
  17. JVM: java虚拟机
  18. 实验10 人机交互的质量与测评
  19. 什么是节流(throttling)和防抖(debouncing)?
  20. java.lang.NullPointerException: Attempt to invoke virtual method 'void com.hhl.library.FlowTagLayout

热门文章

  1. nginx linux 系统服务,把ngnix注册为linux服务 将Nginx设置为linux下的服务
  2. Ubuntu18.04安装OpenCV4.3.0和环境配置(支持编译CUDA并安装配置python-opencv)
  3. 用Java读取文件的5种方法-BufferedReader,FileInputStream,文件,扫描仪,RandomAccessFile
  4. sql 联合_SQL联合,SQL联合全部
  5. scala 协变和逆变_Scala方差:协变,不变和逆变
  6. python类方法_Python类方法
  7. 版权 Copyright 和 Phpstorm
  8. Pointer 指针
  9. 技术人的危机-非理性的繁荣
  10. python迭代器的设计