Интересно, можно ли с архитектурной точки зрения передавать объект в компонент? То, что я на самом деле хочу, это чтобы компонент выставлял наблюдаемое. Однако я хотел бы проконтролировать, откуда исходит этот наблюдаемый поток, поэтому я спрашиваю, можно ли передать объект, где компонент может вызывать «события».
Хорошо, давайте уточним это.
Скажем, мы разрабатываем компонент, который принимает пользовательский ввод, регулирует нажатия клавиш и отображает список результатов. Фактический поиск происходит в другом сервисном компоненте.
Я бы хотел создать функцию создателя SearchWidget следующим образом:
//notice how I just avoided the word "constructor". However, conside this code as
//language agnostic. Could be RxJs or Rx .NET. It's Rx(ish)!
function SearchWidget(userInputStream, resultStream){
// do some funky Rx hotness!
}
Компонент более высокого уровня (скажем, контроллер / посредник) фактически подключит потоки.
Очевидно, что resultStream нужен inputStream, чтобы выполнить работу.
В нашем примере выше, resultStream будет просто наблюдаемым с точки зрения SearchWidget, на котором он может прослушивать список результатов. Однако он будет реализован как субъект в компоненте более высокого уровня.
Напротив, userInputStream будет субъектом с точки зрения SearchWidget, но он будет создан на более высоком уровне компонентов, потому что он нам нужен заранее, чтобы подключить resultStream. Хотя, с точки зрения компонента более высокого уровня, это просто наблюдаемое.
Код высшего порядка может выглядеть так:
//This code lives in a higher order component (say a controller/mediator)
var resultStream = new Rx.Subject();
var userInputStream = new Rx.Subject();
userInputStream
.Throttle(500)
.DistinctUntilChanged()
.Select(service.search) //service comes from somewhere.
.Switch()
.Subscribe(resultStream.OnNext,
resultStream.OnError,
resultStream.OnCompleted);
var searchWidget = new SearchWidget(userInputStream, resultStream.AsObservable());
В приведенной выше реализации я использую userInputStream до инициализации SearchWidget. Конечно, я мог бы также реализовать это так:
//implementation of the search widget
function SearchWidget(resultStream){
var userInputStream = new Rx.Subject();
// provide something like getUserInputStream()
// that will return unserInputStream.AsObservable()
// do some funky Rx hotness!
}
//This code lives in a higher order component (say a controller/mediator)
var resultStream = new Rx.Subject();
var searchWidget = new SearchWidget(resultStream);
//we need to initialize the searchWidget in advance to get the userInputStream
searchWidget
.getUserInputStream()
.Throttle(500)
.DistinctUntilChanged()
.Select(service.search) //service comes from somewhere.
.Switch()
.Subscribe(resultStream.OnNext,
resultStream.OnError,
resultStream.OnCompleted);
Таким образом, с точки зрения инкапсуляции вторая реализация может выглядеть более надежной. Тем не менее, переход к теме обеспечивает большую гибкость.
Поскольку концепция работы с потоками событий довольно современна, я изо всех сил пытаюсь найти лучшие практики для более широкой картины при разработке приложений с потоками событий.