Réflexion sur la mise en place du patron de conception Function Object en Java,
Un tutoriel de Yann Caron

Le , par CyaNnOrangehead

0PARTAGES

2  0 
Bonjour à tous,

Je vous propose un petit article intitulé : « Fonction Object Design pattern - Tutoriel sur les foncteurs - En attendant les lambdas de Java 8 » disponible ici : http://caron-yann.developpez.com/tut...osures-java-8/

Ce tutoriel ce compose comme suit :
  • une présentation du design pattern « function object » ou plus connu sous le nom de foncteur ;
  • une implémentation de celui-ci en Java qui respecte le principe de signature des méthodes en s'appuyant sur les génériques (ce qui n'est pas tout à fait le cas de librairies telles que Guava) ;
  • des cas concrets d'utilisations comme la création de callbacks, l’ajout de méthodes fonctionnelles aux listes (each et map-filter-reduce), parcours depth-first, décorateur fonctionnel et conteneurs IOC.


Cette dernière partie est le résultat d'une discussion ouverte avec, entre autrez, Thierry, que je continuerai très volontiers avec vous.
Elle démontre que Java, depuis la version 5 de son framework, n'a rien à envier à des langages tels que Ruby. Et qu'il n'est pas nécessaire de ce mettre à Groovy pour faire du fonctionnel avec le langage Java.

Et n'oubliez pas de commenter cet article. Vos retours nous aident à améliorer nos publications.

Bonne lecture.

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de professeur shadoko
Membre expérimenté https://www.developpez.com
Le 23/05/2013 à 17:21
Il me semblerait intéressant de compléter avec deux choses:
- un véritable pattern Commande
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface CommandFor<T> {
    public  void invokeOn(T instance);
}

public class CommandForDoer  implements CommandFor<Doer>, Serializable {
    private final String aString ;
    private final int anInt ;

    public CommandForDoer(String aString, int anInt) {
        this.aString = aString;
        this.anInt = anInt;
    }

    @Override
    public void invokeOn(Doer instance) {
        instance.show(aString, anInt);
    }
}
avec utilisations

- un exemple de dynamic Proxy
0  0 
Avatar de CyaNnOrangehead
Rédacteur https://www.developpez.com
Le 23/05/2013 à 17:39
Citation Envoyé par professeur shadoko Voir le message
Il me semblerait intéressant de compléter avec deux choses:
- un véritable pattern Commande
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface CommandFor<T> {
    public  void invokeOn(T instance);
}

public class CommandForDoer  implements CommandFor<Doer>, Serializable {
    private final String aString ;
    private final int anInt ;

    public CommandForDoer(String aString, int anInt) {
        this.aString = aString;
        this.anInt = anInt;
    }

    @Override
    public void invokeOn(Doer instance) {
        instance.show(aString, anInt);
    }
}
avec utilisations
Citation Envoyé par professeur shadoko Voir le message

Oui très bonne idée.
Citation Envoyé par professeur shadoko Voir le message

- un exemple de dynamic Proxy
Excellent, effectivement il y a moyen de faire des trucs pas mal en combinant les deux techniques.
Je regarde dés que j'ai un moment !
0  0 
Avatar de CyaNnOrangehead
Rédacteur https://www.developpez.com
Le 23/05/2013 à 17:54
Voici également la résolution d'un problème que je voulais ajouter :
Compter le nombre de fois ou l'on trouve un mot dans un texte.

Le principe est le suivant :
Un premier map/reduce s'occupe du split "\n"
Un second, à l'intérieur s'occupe de compter les mots "elements"

Voilà ce que ça donne :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
	public void testCountWords() throws Exception {

		String csv = "" +
			"element 1.1, element 1.2, element 1.3, element 1.4\n" +
			"element 2.1, element 2.2\n" +
			"element 3.1, element 3.2, element 3.3\n" +
			"element 4.1, element 4.2, element 4.3, element 4.4, element 4.5\n" +
			"";

		int count = split(csv, "\n").<Integer>map(new Function<Integer, Arguments2<String, Integer>>() {

			@Override
			public Integer invoke(Arguments2<String, Integer> arguments) {
				// the line
				System.out.println("Line : " + arguments.getArgument1());

				return split(arguments.getArgument1(), " ").<Integer>map(new Function<Integer, Arguments2<String, Integer>>() {

					@Override
					public Integer invoke(Arguments2<String, Integer> arguments) {
						// the element
						System.out.println("Word :" + arguments.getArgument1());

						if ("element".equalsIgnoreCase(arguments.getArgument1())) {
							return 1;
						} else {
							return 0;
						}
					}
				}).reduce(new Function<Integer, Arguments2<Integer, Integer>>() {

					@Override
					public Integer invoke(Arguments2<Integer, Integer> arguments) {
						return arguments.getArgument1() + arguments.getArgument2();
					}
				});

			}
		}).reduce(new Function<Integer, Arguments2<Integer, Integer>>() {

			@Override
			public Integer invoke(Arguments2<Integer, Integer> arguments) {
						return arguments.getArgument1() + arguments.getArgument2();
			}
		});

		System.out.println("number of 'element' word in text : " + count);

	}
0  0 
Avatar de LDPDC
Membre régulier https://www.developpez.com
Le 08/10/2013 à 22:17
Merci pour cet article complet mais je ne vois pas très bien l'intérêt de la solution proposée: y-a-t-il un cas d'utilisation réel emblématique qui permettrait de bien comprendre l'utilité concrète de cette implémentation?
0  0 
Avatar de CyaNnOrangehead
Rédacteur https://www.developpez.com
Le 09/10/2013 à 0:04
Citation Envoyé par LDPDC Voir le message
Merci pour cet article complet mais je ne vois pas très bien l'intérêt de la solution proposée: y-a-t-il un cas d'utilisation réel emblématique qui permettrait de bien comprendre l'utilité concrète de cette implémentation?
Salut LDPDC,
Déjà, cet article est un ensemble de réflexions sur le design pattern Function Object.
Le cas concret emblématique c'est la manipulation des listes qui est présentée dans le chapitre map / filter / reduce
Cette approche est complètement différente de l'approche impérative classique de java (et autres).

Le but en soi du fonctionnel à ce niveau est de rendre plus concis et plus lisible le code pour gérer des listes (évidement, avec les générique imposés par java, comme ça, ça ne saute pas aux yeux ).
Guava, bien qu'un petit peu plus limité au niveaux des définitions des foncteurs, propose une très bonne implémentation de ce que j'expose.

Ce week-end, j'ai essayé le langage Scala qui est fondé sur une fusion fonctionnel / objet, on y retrouve tout ça et bien plus. J'y ai écrit les exemples de cet article, et là pour le coup c'est le code source est vraiment concis (moins de 5 lignes pour faire la moyenne des âges chiens mâles d'une liste d'individus).
5 lignes également pour le parcours d'un csv.

L'autre intérêt de tout ceci, c'est surtout de cacher l'implémentation des manipulations de listes à l'utilisateur. Ca permet, entre autre, de faire joujou avec les threads à son insu de façon à optimiser de façon transparent pour l'utilisateur. Un exemple en annexe illustre ceci.
0  0 
Avatar de Nico02
Membre expérimenté https://www.developpez.com
Le 09/10/2013 à 10:18
Un article vraiment intéressant !

J'ai bien aimé le coté "réflexion à haute voix". Ça apporte à mon sens une facilité de lecture et on comprends tout de suite dans quoi on met les pieds.

En bref, je vais me laisser le temps de digérer tout ça, et je pense bien rajouter ce pattern dans ma boite à outils.

Cdt.
0  0 
Avatar de CyaNnOrangehead
Rédacteur https://www.developpez.com
Le 09/10/2013 à 17:35
Citation Envoyé par Nico02 Voir le message
Un article vraiment intéressant !

J'ai bien aimé le coté "réflexion à haute voix". Ça apporte à mon sens une facilité de lecture et on comprends tout de suite dans quoi on met les pieds.

En bref, je vais me laisser le temps de digérer tout ça, et je pense bien rajouter ce pattern dans ma boite à outils.

Cdt.
Oui foncteur est un pattern ultra utile quand on y a goûter.

Après mon implémentation est très puriste sur les arguments, leur nombre et leurs types, mais la contrepartie c'est qu'elle oblige à créer énormément d'objet Arguments et c'est pas idéal pour les performances.
Un interface de ce type est plus rapide :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
public interface Function1 <R, A1> {
  R invoke (A1 arg1);
}

public interface Function2 <R, A1, A2> {
  R invoke (A1 arg1, A2 arg2);
}
0  0 
Responsables bénévoles de la rubrique Java : Mickael Baron - Robin56 -

Partenaire : Hébergement Web