zoukankan      html  css  js  c++  java
  • 理解MVVMLight—Laurent Bugnion的设计思想——〉Service Locator Pattern

      目前Team在写WPF项目的时候,往往设计一个Business Manager类,它是一个Singleton,用来处理一些特定的业务,其实可以理解为Mvc中的Control,也可以理解为一个Service。当业务逻辑的需求需要应用程序的View上交互动作操作,View调用Service来完成特定的任务,如点击PhotoApp,PhotoApp调用Sevice的加载图片方法加载View所需的图片集合。通常最简单的办法是在App Load或者初始化时new创建一个Service对象,或者再高级一点,使用Factory Pattern来Decoupling(解耦)View与Serivce的具体实现部分,通过Config方便的获取该Serivce的实例。然而上述两种做法都有各自的缺陷,下面列述:

      1.在View中直接维护对Serivce的引用,伪代码:

    1 this.Load += Onload;
    2 
    3 private void Onload(object sender,EvenetArgs e){
    4     Service.Instance.Open();
    5 }

      上面是我们项目中经常见到的写法,这样直接造成View与Service之间的依赖关联,当需要替换服务的实现时,必须修改View中调用Service的部分并重新编译Solution。即使采用Factory Pattern来通过Config动态获取Service实例,也无法针对不同的Service向View提供View所需的服务实例。

      2.由于这种依赖关联,使得项目的开发过程受到约束。在实际开发过程中,View开发和Service开发可能是同步进行的,很有可能当View需要调用Service时,Service还没开发完。遇到这种问题,通常先把坑留着,或者自己用Proxy Pattern写个Demo方法,等Service完成后再集成,这种做法不仅费时,增加了合成风险,也使责任不明,更加增加了出错风险提升了测试的复杂度。

      3.针对View的Unit Test变得十分复杂,如果要做Unit Test,无法使用Service Stub来解决View与Service的依赖关系。

      4.在View的Code-Behind中可能存在多处Call Service的Instance,在这种情况下,Service.Instance.Method会散步于整个应用程序中,造成一段代码存在多个副本,几何级的增加了维护和排错的成本。

      5.当View需要Call多个Service时,不同Service 初始化各自的Instance的方式可能存在差异,Coder必须了解所有Service的初始化的API,才能在代码中正确使用这些Service。

      6.某些Service的初始化过程需要耗费大量资源,多次重复初始化,大大增加应用程序的资源占用和性能消耗,项目中需要一个管理Service初始化过程的机制,在统一初始化接口的同时,需要为应用程序提供部分缓存功能,如文稿页面,相册图片等。

      Laurent Bugnion所写的轻量级框架MVVMLight使用Service Locator Pattern来解决上述的问题。

      Service Locator Pattern(服务定位器模式)

        它能够为应用程序中Service的创建和初始化提供一个定位,并解决了上文中所提到的各种设计和开发问题。Service Locator Pattern主要有以下几种参与者:

       1.Service:    

        Service是Service Locator需要返回给调用方的Instance。比如Service Locator(ViewModel Locator)可以根据调用方的需要,View从Service(ViewModel)从网络获取信息,或者View从Service(ViewModel)从本地文件系统获取信息。在这种情形下,这两种Service可能会有着不同的接口:对于前者,它只需要接收一个参数(即需要信息列表)就可以完成获取任务;而对于后者而言,它不仅要获得信息列表,而且还要获得一个正确的文件路径。因此,在实际应用中,我们通常会为不同的Service类型设计不同的接口,而Service Locator则应该根据调用方给定的Service Type,返回相应的Service Instance。

      2.Service Factory

        Service Factory是Factory Pattern的一种实现,它的职责是创建并初始化某种类型的Service。不同的Service Type有其特定的Service Factory,在实际应用中,Service Factory厂与一个特定的Service Intface所对应。使用Service Factory不仅可以Coupling Service的定义部分和具体实现部分,应用程序无需重新编译即可变更Service的不同实现方式,而且对于初始化过程需要消耗大量资源的Service而言,Service Factory还能够提供缓存功能,从而提高应用程序的性能。

      3.Initial Context

        由于不同的Service需要由不同的Service Factory New和实现Initialization,因此对于Service Locator来说,还需要一个特定的Locator来统一管理这些Service Factory,Initial Context就充当了这个角色。在调用方向Service Locator请求一个Service Instance时,Service Locator通过InitialContext获得Service Factory的Instance,然后由Service Factory new service并返回给调用方。使用Initial Context的优点是,它简化了Service Locator的职责,并为Service Factory的管理和缓存提供了有力保障。

      4.Service Locator

        Service Locator为调用方获得所需Service的Instance提供了定位。

      Service Locator Pattern 的类图和时序图请参考Wiki,下面给出的参考资料链接中有,这里就不再引用。

      MVVMLight 实现:

      1.ViewModelLocator(Service Locator)  

    1 <?xml version="1.0" encoding="utf-8"?>
    2 <Application x:Class="WpfApplication1.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:WpfApplication1.ViewModel" mc:Ignorable="d">
    3   <Application.Resources>
    4     <ResourceDictionary>
    5       <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    6       <ResourceDictionary.MergedDictionaries></ResourceDictionary.MergedDictionaries>
    7     </ResourceDictionary>
    8   </Application.Resources>
    9 </Application>

      2. SimpleIoc (Initial Context)

      

     1 using GalaSoft.MvvmLight;
     2 using GalaSoft.MvvmLight.Ioc;
     3 using Microsoft.Practices.ServiceLocation;
     4 
     5 namespace WpfApplication1.ViewModel
     6 {
     7     /// <summary>
     8     /// This class contains static references to all the view models in the
     9     /// application and provides an entry point for the bindings.
    10     /// </summary>
    11     public class ViewModelLocator
    12     {
    13         /// <summary>
    14         /// Initializes a new instance of the ViewModelLocator class.
    15         /// </summary>
    16         public ViewModelLocator()
    17         {
    18             ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
    19 
    20             ////if (ViewModelBase.IsInDesignModeStatic)
    21             ////{
    22             ////    // Create design time view services and models
    23             ////    SimpleIoc.Default.Register<IDataService, DesignDataService>();
    24             ////}
    25             ////else
    26             ////{
    27             ////    // Create run time view services and models
    28             ////    SimpleIoc.Default.Register<IDataService, DataService>();
    29             ////}
    30 
    31             SimpleIoc.Default.Register<MainViewModel>();
    32         }
    33 
    34         public MainViewModel Main
    35         {
    36             get
    37             {
    38                 return ServiceLocator.Current.GetInstance<MainViewModel>();
    39             }
    40         }
    41         
    42         public static void Cleanup()
    43         {
    44             // TODO Clear the ViewModels
    45         }
    46     }

      3.MainWindow.DataContext Binding MainViewModel

        是为View作为调用方引用Service的实例

      具体使用案例:

      1.CodeProject:http://www.codeproject.com/Articles/297624/Implementing-MVVM-Light-with-Structure-Map

      2.GBTouch Team:参考VoteApp实现

      参考资料:

      Deep Dive MVVM: http://channel9.msdn.com/events/MIX/MIX11/OPN03

      MVVMLight:http://www.galasoft.ch/mvvm/

      Service Locator Pattern(Wiki) http://en.wikipedia.org/wiki/Service_locator_pattern

      Service Locator Pattern(MSDN)http://msdn.microsoft.com/en-us/library/ff648968.aspx

      Dependency Injection(MSDN)http://msdn.microsoft.com/en-us/library/dd458879.aspx

      IOC[Inversion of Control]http://msdn.microsoft.com/en-us/library/dd458907.aspx

  • 相关阅读:
    join_tab计算代价
    outer join test
    突然觉得mysql优化器蛮简单
    将数据库字段从float修改为decimal
    小米初体验
    简述安装android开发环境
    Rust语言:安全地并发
    awk里的各种坑
    ubuntu下使用C语言开发一个cgi程序
    Ubuntu下安装和配置Apache2
  • 原文地址:https://www.cnblogs.com/tmywu/p/3099349.html
Copyright © 2011-2022 走看看