Я изучаю, как включить IObservable
в мой код. Ниже приведены два разных подхода к простому классу, который выводит самое последнее слово из IObservable<string>
. Какой подход является более чистым? Мне не нравится WordPrinterWithCache
, потому что он вводит дополнительную переменную состояния (_lastWord
), и интересный код теперь разбросан по всему классу. Я предпочитаю WordPrinterWithExtraSubject
, потому что интересный код локализуется в конструкторе. Но в основном это кажется более последовательно функциональным и «реактивным»; Я реагирую на комбинацию двух «событий»: (1) испускаемое новое слово и (2) вызов метода PrintMostRecent
.Превращение вызова метода в наблюдаемое событие, хорошая идея?
Однако я читал, что использование Субъектов нежелательно, если это не является строго необходимым, и я представляю ненужный Subject<Unit>
. По существу, то, что я здесь делаю, генерирует наблюдаемый из вызова метода, поэтому я могу использовать наблюдаемые функции комбинатора в большем количестве мест. Мне нравится идея создания моего кода с использованием наблюдаемых комбинаторов и подписки, а не с использованием деревьев вызова метода «старого стиля». Я не знаю, хорошая ли это идея.
public class WordPrinterWithCache
{
string _lastWord = string.Empty;
public WordPrinterWithCache(IObservable<string> words)
{
words.Subscribe(w => _lastWord = w);
}
public void PrintMostRecent() => Console.WriteLine(_lastWord);
}
public class WordPrinterWithExtraSubject
{
Subject<Unit> _printRequest = new Subject<Unit>();
public WordPrinterWithExtraSubject(IObservable<string> words)
{
_printRequest
.WithLatestFrom(words.StartWith(string.Empty), (_, w) => w)
.Subscribe(w => Console.WriteLine(w));
}
public void PrintMostRecent() => _printRequest.OnNext(Unit.Default);
}
Фактический сценарий в моем коде является то, что у меня есть ICommand
. Когда пользователь вызывает команду (может быть, нажав кнопку), я хочу принять самое последнее значение определенного наблюдаемого. Например, возможно, ICommand
представляет Delete
, и я хочу удалить выбранный элемент в списке, который представлен IObservable<Guid>
. Ужасно держать кучу переменных кэша «последнего испускаемого значения» для каждого наблюдаемого.
Подход, к которому я склоняюсь, представляет собой реализацию вида ICommand
, как то, что вы видите ниже. Это позволяет мне писать код, как deleteCommand.WithLatestFrom(selectedItems,(d,s)=>s).Subscribe(selected=>delete(selected));
public class ObservableCommand : ICommand, IObservable<object>
{
bool _mostRecentCanExecute = true;
Subject<object> _executeRequested = new Subject<object>();
public ObservableCommand(IObservable<bool> canExecute)
{
canExecute.Subscribe(c => _mostRecentCanExecute = c);
}
public event EventHandler CanExecuteChanged; // not implemented yet
public bool CanExecute(object parameter) => _mostRecentCanExecute;
public void Execute(object parameter) => _executeRequested.OnNext(parameter);
public IDisposable Subscribe(IObserver<object> observer) => _executeRequested.Subscribe(observer);
}
Я создаю свою собственную реактивную структуру MVVM, чтобы узнать, могу ли я прийти к нирване сверхпростого декларативного кода. Подход к вашему блогу довольно увлекательный. Он отличается от того, что у меня есть несколькими способами. (1) Я выставляю ObservableProperty непосредственно в представление как свойство только для чтения, а затем привязываюсь к свойству Value - меньше кода. (2) Моя команда принимает IObservable , чтобы определить, включена ли она - более декларативная. (3) Использование одного метода для поведения - это действительно крутая идея; мой конструктор стал слишком большим и функциональным, это спагетти. –
JustinM
Привет, Джастин, рад, что вы нашли сообщение в блоге информативным. Пара вопросов о ваших комментариях: (1) Осуществляет ли ваш ObservableProperty INotifyPropertyChange? (2) Моя команда - это IObserver, а не IObservable как параметр конструктора и имеющая (внутреннюю и потенциально протекающую) подписку на наблюдаемую. (3) Я склонен помещать объявление поведения в вызов Initialize вместо конструктора, но это был всего лишь пример. Удачи вам в вашей карьере! –
ibebbs
О, также я бы рекомендовал написать «библиотеку», а не «фреймворк». Отличный пост по этому вопросу (и разница!) Здесь: http://tomasp.net/blog/2015/library-frameworks/ Просто о чем подумать, пока вы занимаетесь архитектурой ... – ibebbs