Last active
September 22, 2017 22:15
-
-
Save vaughandroid/1feaf1eb79552cdd93e70cfdee40710f to your computer and use it in GitHub Desktop.
Experimenting with Rx architecture
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Wiring { | |
private final Observable<ViewModel> viewModelObservable; | |
Wiring(View view, ActionDispatcher actionDispatcher, Service service, ViewModelScanner viewModelScanner) { | |
viewModelObservable = view.uiEventObservable() | |
.compose(actionDispatcher.uiEventToAction()) | |
.compose(service.actionToResult()) | |
.compose(viewModelScanner.resultToViewModel()); | |
} | |
public Observable<ViewModel> viewModelObservable() { | |
return viewModelObservable; | |
} | |
} | |
interface View { | |
Observable<UiEvent> uiEventObservable(); | |
} | |
class ActionDispatcher { | |
ObservableTransformer<UiEvent, Action> uiEventToAction() { | |
ObservableTransformer<TextUpdated, Action> textUpdatedToAction = | |
events -> events | |
.flatMap(textUpdated -> Observable.just(new GetAutocomplete(textUpdated.text))); | |
ObservableTransformer<SubmitClicked, Action> submitClickedToAction = | |
events -> events | |
.flatMap(submitClicked -> Observable.just(new Submit(), new SendAnalytics("submit"))); | |
return events -> events | |
.publish(shared -> Observable.merge( | |
shared.ofType(TextUpdated.class).compose(textUpdatedToAction), | |
shared.ofType(SubmitClicked.class).compose(submitClickedToAction) | |
)); | |
} | |
} | |
class Service { | |
private final AutocompleteService autocompleteService; | |
private final SubmitService submitService; | |
public Service(AutocompleteService autocompleteService, SubmitService submitService) { | |
this.autocompleteService = autocompleteService; | |
this.submitService = submitService; | |
} | |
ObservableTransformer<Action, Result> actionToResult() { | |
return events -> events | |
.publish(shared -> Observable.merge( | |
shared.ofType(GetAutocomplete.class).compose(autocompleteService.transformer()), | |
shared.ofType(Submit.class).compose(submitService.transformer()) | |
)); | |
} | |
} | |
class SubmitService { | |
ObservableTransformer<Submit, SubmitResult> transformer() { | |
return events -> events | |
.flatMap(submit -> { | |
return Observable.just(SubmitResult.IN_FLIGHT, SubmitResult.SUCCESS); | |
}); | |
} | |
} | |
class AutocompleteService { | |
ObservableTransformer<GetAutocomplete, AutoCompleteResult> transformer() { | |
return events -> events | |
.flatMap(getAutocomplete -> { | |
String[] results = new String[3]; | |
results[0] = getAutocomplete.text + "a"; | |
results[1] = getAutocomplete.text + "b"; | |
results[2] = getAutocomplete.text + "c"; | |
return Observable.just( | |
AutoCompleteResult.IN_FLIGHT, | |
AutoCompleteResult.success(results) | |
); | |
}); | |
} | |
} | |
class ViewModelScanner { | |
ObservableTransformer<Result, ViewModel> resultToViewModel() { | |
return events -> events | |
.scan(ViewModel.initial(), (viewModel, result) -> { | |
viewModel = viewModel.copy(); | |
viewModel.isLoading = (result == AutoCompleteResult.IN_FLIGHT | |
|| result == SubmitResult.IN_FLIGHT); | |
viewModel.submitButtonClickable = result != SubmitResult.IN_FLIGHT; | |
if (result == AutoCompleteResult.ERROR || | |
result == SubmitResult.ERROR) { | |
viewModel.autocompleteOptions = null; | |
viewModel.text = "ERROR!"; | |
} else if (result instanceof AutocompleteSuccessResult) { | |
viewModel.autocompleteOptions = ((AutocompleteSuccessResult) result).autocompletes; | |
} else if (result == SubmitResult.SUCCESS) { | |
viewModel.text = "SUCCESS!"; | |
} | |
return viewModel; | |
}) | |
.cache(); | |
} | |
} | |
abstract class UiEvent { | |
static class TextUpdated extends UiEvent { | |
final String text; | |
TextUpdated(String text) { | |
this.text = text; | |
} | |
} | |
static class SubmitClicked extends UiEvent { | |
} | |
} | |
class ViewModel { | |
public static ViewModel initial() { | |
return new ViewModel(); | |
} | |
String text; | |
String[] autocompleteOptions; | |
boolean submitButtonClickable = true; | |
boolean isLoading; | |
ViewModel copy() { | |
ViewModel result = new ViewModel(); | |
result.text = text; | |
result.autocompleteOptions = autocompleteOptions; | |
result.submitButtonClickable = submitButtonClickable; | |
result.isLoading = isLoading; | |
return result; | |
} | |
} | |
abstract class Action { | |
static class GetAutocomplete extends Action { | |
final String text; | |
GetAutocomplete(String text) { | |
this.text = text; | |
} | |
} | |
static class Submit extends Action { | |
} | |
static class SendAnalytics extends Action { | |
final String event; | |
SendAnalytics(String event) { | |
this.event = event; | |
} | |
} | |
} | |
abstract class Result { | |
static class AutoCompleteResult extends Result { | |
public static final AutoCompleteResult IN_FLIGHT = new AutoCompleteResult(); | |
public static final AutoCompleteResult ERROR = new AutoCompleteResult(); | |
public static AutocompleteSuccessResult success(String... autocompletes) { | |
return new AutocompleteSuccessResult(autocompletes); | |
} | |
static class AutocompleteSuccessResult extends AutoCompleteResult { | |
final String[] autocompletes; | |
AutocompleteSuccessResult(String[] autocompletes) { | |
this.autocompletes = autocompletes; | |
} | |
} | |
} | |
static class SubmitResult extends Result { | |
public static final SubmitResult IN_FLIGHT = new SubmitResult(); | |
public static final SubmitResult SUCCESS = new SubmitResult(); | |
public static final SubmitResult ERROR = new SubmitResult(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment