ReactiveUI、视图/视图模型注入和依赖注入的概述

13

最近我一直在尝试进入新的UI开发时代,并发现了ReactiveUI。我喜欢它的声明性特质。

我想完全切换,所以我试图了解在这个ReactiveUI的新世界中如何制作东西。我选择ReactiveUI是因为我看到它由一个非常聪明的人(Paul C. Betts)维护。

我很新手,可能会在StackOverflow上提出关于它的问题,因为它有很大的能量,我认为它值得学习和掌握。

让我们深入细节:

我一直使用视图优先。我是Cinch Framework(http://cinch.codeplex.com/)的老用户

它使用MEF将ViewModel注入到每个View中。您只需用[ViewModel("SampleView")]装饰您的ViewModel,并为您的View添加一个附加属性(ViewModelLocator.ViewModel =“SampleView”),每当View加载时,对应的ViewModel将根据您选择的生命周期进行实例化并注入为其DataContext。

虽然该机制有效,但它也存在一些不便之处,其中最糟糕的是:它使用了定位器。

正如Mark Seemann在他的书中建议的那样,ServiceLocator是一个应该避免使用的反模式。

  1. 所以我的第一个问题是:ReactiveUI是建立在基于定位器的基础设施之上吗?
  2. 视图优先还是ViewModel优先? 对于像我这样疯狂地喜欢微软Clean Code的人来说,哪个更好,涉及解耦、SOLID等这些问题?哪一个会让我睡得更好,并为我的应用程序提供所有这些*ibility的好处?
2个回答

28

ServiceLocator是一种应该避免使用的反模式。

我认为在“跨平台移动应用程序”领域中,IoC/DI建议的大部分内容都相当糟糕,因为您必须记住,这些想法的很多是针对Web应用编写的,而不是移动应用或桌面应用。

例如,绝大多数流行的IoC容器仅关注在暖缓存上的解析速度,而基本上完全忽略了内存使用或启动时间 - 这对于服务器应用程序来说是完全可以的,因为这些事情并不重要;但对于移动应用?启动时间非常重要。

Splat的服务定位解决了RxUI的许多问题:

  1. 服务定位很快,并且几乎没有设置开销。
  2. 通过以不同的方式编写Func,它封装了几种常见的对象生命周期模型(即“每次创建新对象”,“单例”,“惰性”)
  3. 它对Mono链接器友好(通常)
  4. 服务定位允许我们在特定于平台的代码中注册类型,但在PCL代码中使用它们。

使用服务定位的最佳方法

实际上,我确实同意Mark Seemann的观点,即构造函数注入是首选的方法 - 这是我真正喜欢的模式:

    public SuspensionHost(ISuspensionDriver driver = null)
    {
        driver = driver ?? Locator.Current.GetService<ISuspensionDriver>();
    }

如果调用方没有在构造函数中显式提供接口,则默认使用服务定位接口。这比尝试构建虚假IoC容器在单元测试运行器中进行测试要简单得多,但仍会在运行时回退到默认实现。

首先视图还是首先视图模型?

在ReactiveUI中是否可以使用基于VM的路由(例如RoutedViewHost、IScreen、RoutingState等)取决于您所在的平台:

  • WPF、Xamarin Forms:绝对可行
  • WP8、WinRT:你可以让它工作,但会失去一些转换效果和美观性
  • Android、iOS原生:非常难以实现

1
看看 DryIoc.Zero,它解决了慢注册的问题,同时提供了惊人的功能。 - Grigory
1
我仍然不喜欢依赖于静态定位器而不是注入接口类型的事实,后者可以在外部项目中轻松模拟。至少应该有一种选项来避免使用当前形式的“定位器”。 - Shimmy Weitzhandler
关于路由,是否有一种跨平台的技术来引导和路由?我正在启动一个新的客户项目,将使用Uno Platform编写,因为我可以编写一个简单的UWP应用程序,在桌面、移动设备和Web上进行编译和渲染。谢谢! - Shimmy Weitzhandler

6

保罗可能会给出官方答案,但我作为一个已经在几个项目中使用了这个框架但并不是专家的人,想提供一些自己的看法。

1)我很欣赏马克·西曼(Mark Seemann)的观点,也同意他对ServiceLocator反模式的结论。虽然ReactiveUI确实使用了Locator "Splat",但我认为它并没有建立在基于Locator的基础架构之上。有一些全局项被用作线程调度器和一些重要的设置,但这些主要是在应用程序启动时设置(就像任何DI容器),而且你在大多数情况下不会直接在类中处理它们。唯一的真正位置是ViewModelHost控件,它使用特定的接口(IViewFor)在视图上注册以进行ViewModels。这比属性方法更好,因为它使ViewModels对Views无感知。但这发生在控件本身并且是框架的一部分,所以我认为它不是ServiceLocator反模式的滥用。在设置DI容器时,我认为这与注册其他所有内容没有什么不同。

2)从我使用ReactiveUI的经验来看,我的视图变得非常简单。基本上只需编写一些基本的XAML以正确设置外观和布局,在代码后台实现IViewFor,并在构造函数中进行所有的绑定。我现在发现使用ReactiveUI比在XAML中进行绑定更容易。然后,所有的逻辑都在ViewModels中完成。我认为我通常采用ViewModel First方法,仅仅是因为我需要为视图实现IViewFor<>时定义它(或者至少是它的接口)。我喜欢类型检查等功能(这也是我喜欢在构造函数而不是在XAML中进行绑定的另一个原因)。但从我的经验来看,我认为没有选择哪种方法较好的强烈理由。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接