web-dev-qa-db-fra.com

composer () vs transformer () vs as () vs map () dans Flux et Mono

Récemment, j'ai décidé d'essayer le printemps 5 avec projectreactor.io (io.projectreactor: 3.1.1).

Quelqu'un sait-il quel est le meilleur cas d'utilisation de ces fonctions? Quels inconvénients et avantages à utiliser chacun d'eux et où les utiliser?

De bons exemples seront utiles.

13
Andrew Sasha

Vous avez ici deux catégories d'opérateurs très différentes:

Opérateurs qui travaillent sur le Flux lui-même

transform et compose sont pour la mutualisation de code

Lorsque vous composez régulièrement des chaînes d'opérateurs et que vous avez des modèles d'utilisation d'opérateurs communs dans votre application, vous pouvez mutualiser ce code ou lui donner un nom plus descriptif en utilisant compose et transform.

La différence entre les deux est lorsque les opérateurs mutualisés sont appliqués: transform les applique à l'instanciation, tandis que compose s'applique les souscrire (permettant un choix dynamique des opérateurs ajoutés).

Jetez un œil à la documentation de référence pour plus de détails et d'exemples.

as

Il s'agit d'un raccourci pratique pour appliquer un Function à l'ensemble Flux tout en conservant le code entier dans un style fluide. Un exemple serait de convertir en Mono (comme indiqué dans le javadoc), mais cela peut également aider avec les opérateurs externes qui sont implémentés dans un style de méthode d'usine.

Prenez reactor-addonsMathFlux par exemple, et comparez:

MathFlux.sumInt(Flux.range(1, 10)
                    .map(i -> i + 2)
                    .map(i -> i * 10))
        .map(isum -> "sum=" + isum);

À:

Flux.range(1, 10)
    .map(i -> i + 2)
    .map(i -> i * 10)
    .as(MathFlux::sumInt)
    .map(isum -> "sum=" + isum)

(cela peut vous aider à faire face au fait que, contrairement à Kotlin, Java n'a pas de méthodes d'extension :))

Opérateur qui travaille sur les données qui passent par le Flux

map concerne les données. Il applique une fonction de transformation 1-1 à chaque élément de la source, à mesure qu'ils deviennent disponibles.

Dans l'exemple MathFlux ci-dessus, map est utilisé successivement pour ajouter 2 à chaque entier d'origine, puis à nouveau pour multiplier chaque nombre de la séquence par 10, puis une troisième fois à la fin pour produire un String sur chaque somme.

15
Simon Baslé

J'ai trouvé l'exemple dans documentation de référence peu difficile à suivre

J'ai donc fait les programmes ci-dessous pour envelopper ma tête autour du concept tranform vs compose.

fnstatefull = flux -> {
                            Flux<String> f = flux.filter(color -> {
                                //only reds are allowed
                                return color.equalsIgnoreCase("red");   

                            });
                            //applies mapping 'toUpperCase' based on the external control 'toUpper'
                            if(toUpper) {
                                f= f.map(String::toUpperCase);
                            }
                            return f;
                        };

Transformer

L'opérateur est appliqué au moment de instanciation du flux.

fnstatefull se comportera de la même manière pour les deux abonnés ci-dessous.

    Flux<String> f = Flux.just("red", "green", "blue");
    toUpper = false;
    f = f.transform(fnstatefull);
    toUpper = true;

    f.subscribe(op -> log.error("ONE>>>" + op));
    toUpper = false;
    f.subscribe(op -> log.error("TWO>>>" + op));

Production

ReactordemoApplication - ONE>>>red
ReactordemoApplication - TWO>>>red

Composer

L'opérateur est appliqué lors de abonnement au flux.

fnstatefull se comportera différemment pour chaque abonné ci-dessous.

    Flux<String> f = Flux.just("red", "green", "blue");
    toUpper = false;
    f = f.compose(fnstatefull);
    toUpper = true;

    f.subscribe(op -> log.error("ONE>>>" + op));
    toUpper = false;
    f.subscribe(op -> log.error("TWO>>>" + op));

Production

ReactordemoApplication - ONE>>>RED
ReactordemoApplication - TWO>>>red
2
Vasco