Refactorer votre code avec la programmation fonctionnelle (Sauce Java)

Lors de mon passage à Devoxx 2017 j’ai pu apprendre comment refactorer son code grâce à la programmation fonctionnelle. Simple efficace, disons même élégant, j'ai pu gagner quelques lignes de code facilement.

Prenons l’exemple simple ci-dessous.

Nous avons un webservice Java qui contient deux méthodes (GetDossier et GetCommande).

Chacun fait appel à son propre service afin d'effectuer un appel en base de données.

/**
 * Controleur pour la recherche des Commandes et Dossiers
 * @author Netapsys
 */
@RestController
@RequestMapping("/api/recherche")
public class RechercheController {


		@Autowired
    	RechercheService rechercheCommandeService;

    	@Autowired
    	RechercheService rechercheDossierService;

		@RequestMapping(method = RequestMethod.GET)
		public Iterable<Response> getCommande(@RequestParam(value = "searchText") String searchText,
									Pageable pageable,
									Principal principal) {
	
			return this.rechercheCommandeService.getResponse(searchText);
		}

		@RequestMapping(method = RequestMethod.GET)
		public Iterable<Response> getDossier(@RequestParam(value = "searchText") String searchText,
									Pageable pageable,
									Principal principal) {
			return this.rechercheDossierService.getResponse(searchText);
		}
}

Nous avons donc deux services 'rechercheDossierService' et 'rechercheCommandeService'.

Partons du postulat que les deux services ont énormément de point communs (La connexion à la base de données, la méthode de formatage du texte en entré ou encore la manipulation des données pour les rendre compatibles avec le format de retour).

Une seule méthode les différencie "Le formatage des données à retourner".

Afin de simplifier notre code, plusieurs possibilités s’offrent à nous.

  • Créer une class parent qui va traiter les méthodes communes des deux class filles
  • Créer une class utilitaire qui va s'occuper des activités transverses (Manipulation des données, Connexion à la base etc...)
  • Ou ... Passer par la programmation fonctionnelle "Sauce Java (8)"

Avec la programmation fonctionnelle nous pouvons refactorer notre code comme suivant :

  • Step 1 : Redéfinir dans la classe controller nos deux méthodes différenciantes et passer en paramètre la méthode à la classe service.
  • Step 2 : Créer une seule class de recherche qui contient l'ensemble des méthodes communes.
  • Step 3 : Définir l'appel dans la classe de service à la méthode différenciante

Ci-dessous le step 1 (La classe controller refactorer)

/**
 * Controlleur pour la recherche des Commandes et Dossiers
 * @author Netapsys
 */
@RestController
@RequestMapping("/api/recherche")
public class RechercheController {


		@Autowired
    	RechercheService rechercheService;

		@RequestMapping(method = RequestMethod.GET)
		public Iterable<Response> getCommande(@RequestParam(value = "searchText") String searchText,
									Pageable pageable,
									Principal principal) {
	
			//Step 1 passage en parametre de la méthode getResultFromDossierResponse
			return this.rechercheService.getResponse(searchText,RechercheController::getResultFromDossierResponse););
		}

		@RequestMapping(method = RequestMethod.GET)
		public Iterable<Response> getDossier(@RequestParam(value = "searchText") String searchText,
									Pageable pageable,
									Principal principal) {

			//Step 1 passage en parametre de la méthode getResultFromCommandeResponse
			return this.rechercheService.getResponse(searchText,RechercheController::getResultFromCommandeResponse););
		}

		private static Map<String, String> getResultFromDossierResponse(SearchResponse response) {
   			// Some code to return
		}


		private static Map<String, String> getResultFromCommandeResponse(SearchResponse response) {
   			// Some code to return
		}
}

Ci-dessous le Step 2 et 3 (redéfinition d'une seule class de service et appel à la méthode passée en paramètre)

// Step 2 Re-Définition d'une seule class de service
 public Iterable<Response> getResponse(String searchText,
            Function<SearchResponse, Map<String, String> map) throws IOException, JSONException {

			// Some code
			
			//Step 3 appel à la méthode passée en paramétre
        	Map<String, String> result = map.apply(response);

        	// Some code
            }

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *