POO & Design Patterns

Le patron Strategy

Le patron Strategy

Le patron Strategy est un patron comportemental du GoF qui permet de faire varier l'algorithme (i.e. le code) utilisé dans une classe.

L'idée est d'utiliser un objet pour simplement fournir du code et de définir une interface commune à ces objets.

En d'autres termes, c'est que vous faîtes à chaque fois qu'une classe ou une méthode prend en paramètre une lambda.

Par exemple, dans l'API Java, la méthode de tri List<T>.sort(Comparator<? super T>) prend en paramètre le code permettant de comparer deux éléments.

Exemple

record Credential(String login, String password) { ... }

class ConnexionHandler {
    // ...
    
    private boolean isSecured(Crendential credential){
         if (!Pattern.compile("[a-z]+").matcher(credential.login()).matches()){
             return false;
         }
         return credential.password().length()>=8;
    }

    public void connect(Credential credential) {
    	if (!isSecured(credential)){
    		...
    	}
    }
}

On veut pouvoir faire évoluer la vérification des indentifiants en respectant le principe Open-Close.

Exemple

Respecter le principe Open-Close, c'est pouvoir changer la façon de valider les identifiants simplement en rajoutant des classes mais sans modifier à chaque fois la classe ConnectionHandler.

Idéalement, on voudrait:

// ancien comportement
var connectionHandler = new ConnectionHandler(); 

// nouveau comportement
var connectionHandler2 = new ConnectionHandler( code de validation ); 

Exemple

@FunctionalInterface
interface CredentialValidator {
    boolean isSecure(Credential credential);
}
class ConnectionHandler {
    private final static PasswordValidator DEFAULT_VALIDATOR = s -> {
    	if (!Pattern.compile("[a-z]+").matcher(credential.login()).matches()){
             return false;
         }
         return credential.password().length()>=8;
    }

    private final CredentialValidator validator;

    public void ConnectionHandler(){
    	this.validator = DEFAULT_VALIDATOR;
    }

    public void ConnectionHandler(CredentialValidator validator){
         this.validator = Objects.requireNonNull(validator);
    }     
    // ...
    private boolean isSecured(Crendential cred){
         return validator.isSecured(credential);
    }
}

Remarques historiques

Le patron strategy pré-date l'introduction des lambdas en Java. Le principe était le même, on définissait une interface et l'on prenait un objet implémentant cette interface.

L'interface CredentialValidator est identique à Predicate<Credential>. Ici, on a fait le choix de nommer l'interface pour rendre le code plus accessible à des non-spécialistes des lambdas.