将 IObservable 传递给构造函数 - 好主意? [英] Passing an IObservable to a constructor - good idea?

查看:31
本文介绍了将 IObservable 传递给构造函数 - 好主意?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我阅读了评论这个关于如何使用 IObservable 的网站说..

I read a comment on this web site about how to use IObservable that said..

作为一般规则(指南),我强烈建议不要将 IObservable 作为方法的参数.明显的警告是,如果该方法是一个新的 Rx 运算符,例如SelectMySpecialBufferDebounce

As a general rule (guideline), I strongly suggest not having an IObservable<T> as a parameter to a method. The obvious caveat being if that method is a new Rx Operator e.g. Select, MySpecialBuffer, Debounce etc.

所以我一直在尝试将这个建议应用到我的代码中,并不断遇到打破这个规则似乎很方便的情况.看看下面的代码并比较PersonSelectorViewModelAPersonSelectorViewModelB.这些视图模型可能绑定到 ComboBox 的 ItemsSource 和 SelectedValue 属性.

So I've been trying to apply this advice to my code and keep running into situations where it seems convenient to break this rule. Take a look at the code below and compare PersonSelectorViewModelA and PersonSelectorViewModelB. These view models might be bound to the ItemsSource and SelectedValue properties of a ComboBox.

我喜欢 PersonSelectorViewModelA - 它在构造函数中使用 IObservable - 更好,因为一旦它被构造,它会自动响应添加到地址簿和从地址簿添加的人.它在没有任何保姆的情况下处理其业务和责任.PersonSelectorViewModelB 需要更多的维护和照顾",因为实例化它的代码需要记住定期调用 UpdatePeople.

I like PersonSelectorViewModelA - which takes an IObservable in the constructor - better because once it is constructed it automatically responds to people being added to and from the address book. It takes care of its business and responsibilities without any babysitting. PersonSelectorViewModelB requires more "maintenance and care" since code that instantiates it needs to remember to periodically call UpdatePeople.

那么哪种方法更好?

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Guid Id { get; set; }
}

public interface IAddressBookRepository
{
    void AddOrUpdatePerson(Person p);
    void DeletePerson(Guid id);
    IObservable<IEnumerable<Person>> People();
}

public class PersonSelectorViewModelA : BindableBase
{
    Guid? _selectedPersonId = null;
    ObservableCollection<Person> _peopleCollection = new ObservableCollection<Person>();
    IObservable<IEnumerable<Person>> _peopleSource;
    IDisposable _subscription;

    public PersonSelectorViewModelA(IObservable<IEnumerable<Person>> people)
    {
        _peopleSource = people;
    }

    public void OnNavigateTo()
    {
        _subscription =
            _peopleSource
            .Select(i => i.ToArray())
            .Subscribe(i =>
            {
                _peopleCollection.Clear();
                foreach (var p in i)
                {
                    _peopleCollection.Add(p);
                }
                if (!i.Any(j => j.Id == SelectedPersonId))
                {
                    SelectedPersonId = null;
                }
            });
    }

    public void OnNavigateAway() => _subscription?.Dispose();

    public Guid? SelectedPersonId {
        get { return _selectedPersonId; }
        set { SetProperty(ref _selectedPersonId, value); }
    }

    public ObservableCollection<Person> People => _peopleCollection;
}

public class PersonSelectorViewModelB : BindableBase
{
    Guid? _selectedPersonId = null;
    ObservableCollection<Person> _peopleCollection = new ObservableCollection<Person>();

    public void UpdatePeople(IEnumerable<Person> people)
    {
        _peopleCollection.Clear();
        foreach (var p in people)
        {
            _peopleCollection.Add(p);
        }
        if (!people.Any(j => j.Id == SelectedPersonId))
        {
            SelectedPersonId = null;
        }
    }

    public Guid? SelectedPersonId {
        get { return _selectedPersonId; }
        set { SetProperty(ref _selectedPersonId, value); }
    }

    public ObservableCollection<Person> People => _peopleCollection;
}

推荐答案

在响应式 ICommand 的情况下,命令主机通常会知道何时启用和禁用命令,并且可以手动(外部)执行此操作,而不是构建一个IObservable 然后将其传递给命令的构造函数.显示 FirstName 和 LastName 的串联的响应式 FullName 属性也是如此;使 FullName 成为 IObserver 更简单,而不是构建 IObservable 并将其传递给 FullName 属性的构造函数.所以对于这些例子,我明白你的意思.

In the case of a reactive ICommand, the command host will often know when to enable and disable the command and could do that manually (externally) rather than constructing an IObservable just to then pass it into the command's constructor. Same goes for reactive FullName property that displays a concatenation of FirstName and LastName; simpler to make FullName an IObserver rather than building an IObservable and passing it into the constructor of the FullName property. So for these examples I see your point.

我的数据层有像IObservable这样的功能.GetPeople(string city)IObservableGetPerson(Guid id) 以便视图可以显示最新信息.这一层不知道它的消费者是谁;有许多视图模型需要这些数据.假设一个消费者是另一个视图模型 X 托管的人员选择器"视图模型.而不是让 X 订阅可观察对象并从外部驱动它拥有的人员选择器",我在其构造函数中为人员选择器"提供可观察对象所以 X 可以放手更多.X 不关心人员选择器如何完成它的工作——它只是想让它做它.X知道"可观察对象,但只知道从某个数据层获取它并使用它来构建人员选择器所必需的.

My data layer has functions like IObservable<Person[]> GetPeople(string city) and IObservable<Person> GetPerson(Guid id) so views can display up-to-date info. This layer doesn't know who its consumers are; there are many view models that need this data. Suppose one consumer is a "people picker" view model hosted by another view model X. Rather than have X subscribe to the observable and externally drive the "people picker" that it owns, I give the "people picker" the observable in its constructor so X can be more hands off. X doesn't care about how the people picker does its job - it just wants it to do it. X "knows about" the observable, but only so much as is necessary to grab it from some data layer and use it to construct the people picker.

我认为这类似于 WPF ListView.您可以将 ListView 的 ItemsSource 属性设置为支持 INotifyCollectionChanged 的​​集合,然后 ListView 订阅事件并自动更新其内容.这种数据绑定比让拥有 ListView 的视图模型订阅列表更改并在 ListView 上调用某些 UpdateItems 方法要简单.

I think this is similar to a WPF ListView. You can set the ItemsSource property of a ListView to a collection that supports INotifyCollectionChanged and then the ListView subscribes to events and automatically updates its contents. This data binding is simpler than having the view model that owns the ListView subscribe to list changes and call some UpdateItems method on the ListView.

这听起来像是在说几乎从不将 observable 传递给对象的构造函数.所以从构造函数依赖注入的角度考虑,一个类不应该依赖于一个可观察的序列.但这不可能是正确的,并且可能不是您所说的.也许我没有正确解释原始问题中的场景.否则,一个类只能依赖它创建的 observables(很奇怪)或它通过对其依赖项的方法调用获取的 observables(类似于构造函数注入).

It sounds like you are saying to almost never pass an observable to the constructor of an object. So thinking in terms of constructor dependency injection, a class shouldn't depend on an observable sequence. But this can't be right and is probably not what you are saying. Maybe I didn't properly explain the scenario in the original question. Otherwise a class could only depend on observables it creates (weird) or observables it grabs through method calls to its dependencies (similar to constructor injection).

这篇关于将 IObservable 传递给构造函数 - 好主意?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆