Application Pratique des Patrons de Conception : Méthode Modèle et Stratégie en Java

Patron Méthode Modèle

Définition du Patron Méthode Modèle : Il s'agit de définir l'ossature d'un algorithme dans une méthode, tout en reportant certaines étapes à des sous-classes. Cela permet aux sous-classes de redéfinir des parties spécifiques de l'algorithme sans en modifier la structure globale.

Classe Abstraite

Créons une classe abstraite AbstractServiceNoeudAgricole qui représente un service pour gérer les enregistrements liés aux nœuds de travail agricole.


public abstract class AbstractServiceNoeudAgricole {

    // Simulations de services de persistance
    private String serviceReglesPlanPlantation = "serviceReglesPlanPlantation";
    private String serviceInfoPlanPlantation = "serviceInfoPlanPlantation";
    private String serviceEcartRegles = "serviceEcartRegles";

    /**
     * Méthode modèle finale définissant l'algorithme de traitement complet.
     */
    final void insererNoeudAgricoleComplet(String typeNœud) {
        // Étape 1 : Insérer l'enregistrement courant
        insererEnregistrementActuel();
        // Étape 2 : Insérer les données de terre
        insererTerresParLot();
        // Étape 3 : Mettre à jour les règles du plan de plantation
        mettreAJourReglesPlanPlantation();
        // Étape 4 : Mettre à jour la table des écarts de règles
        calculerEcartReglesPlanPlantation(typeNœud);
        // Étape 5 : Mettre à jour le statut d'opération du nœud
        mettreAJourStatutOperationNoeud(typeNœud);
    }

    /**
     * Méthodes abstraites à implémenter par les sous-classes pour les étapes spécifiques.
     */
    abstract void insererEnregistrementActuel();
    abstract void insererTerresParLot();

    /**
     * Met à jour uniquement les règles du nœud courant.
     */
    void mettreAJourReglesSoiMeme() {
        System.out.println("3. " + serviceReglesPlanPlantation + "\tMise à jour des règles pour le nœud courant uniquement");
    }

    /**
     * Met à jour les règles du nœud courant et de ses successeurs.
     */
    void mettreAJourReglesSoiMemeEtDescendants() {
        System.out.println("3. " + serviceInfoPlanPlantation + "\tMise à jour des règles pour le nœud courant et ses descendants");
    }

    /**
     * Calcule et met à jour la table des écarts de règles.
     */
    void calculerEcartReglesPlanPlantation(String typeNœud) {
        System.out.println("4. " + serviceEcartRegles + "\t【" + typeNœud + "】Calcul de l'écart des règles");
    }

    /**
     * Met à jour le statut d'opération (parent ou enfant).
     */
    void mettreAJourStatutOperationNoeud(String typeNœud) {
        System.out.println("5. " + serviceReglesPlanPlantation + "\t【" + typeNœud + "】Mise à jour du statut de l'opération");
    }

    /**
     * Fonction crochet pour déterminer le comportement de mise à jour des règles.
     * @return true pour mettre à jour uniquement le nœud courant, false pour inclure les descendants.
     */
    boolean estMiseAJourUniquementSoiMeme() {
        return true;
    }

    /**
     * Méthode finale qui utilise la fonction crochet pour appeler la logique appropriée.
     */
    final void mettreAJourReglesPlanPlantation() {
        if (estMiseAJourUniquementSoiMeme()) {
            mettreAJourReglesSoiMeme();
        } else {
            mettreAJourReglesSoiMemeEtDescendants();
        }
    }
}

Optimisation via le Patron Méthode Modèle : Nous avons d'abord abstrait les opérations métier en une séquence d'étapes codifiées dans la méthode modèle. Les étapes communes sont implémentées dans la superclasse, tandis que les étapes variables sont déléguées aux sous-classes sous forme de méthodes abstraites. L'utilisation d'une fonction crochet (estMiseAJourUniquementSoiMeme) permet de contrôler dynamiquement le comportement de l'algorithme.

Implémentations des Sous-Classes

Sous-classe pour l'étape de démarrage :


public class ServiceNoeudAgricoleEtapeDemarrage extends AbstractServiceNoeudAgricole {

    private String persistanceEnregistrement = "persistanceEnregistrementDemarrage";
    private String persistanceTerre = "persistanceTerreDemarrage";

    @Override
    void insererEnregistrementActuel() {
        System.out.println("1. " + persistanceEnregistrement + "\tInsertion de l'enregistrement de démarrage");
    }

    @Override
    void insererTerresParLot() {
        System.out.println("2. " + persistanceTerre + "\tInsertion des terres pour l'étape de démarrage");
    }
}

Sous-classe pour l'étape de pulvérisation, qui redéfinit la fonction crochet :


public class ServiceNoeudAgricoleEtapePulverisation extends AbstractServiceNoeudAgricole {

    private String persistanceEnregistrement = "persistanceEnregistrementPulverisation";
    private String persistanceTerre = "persistanceTerrePulverisation";

    @Override
    void insererEnregistrementActuel() {
        System.out.println("1. " + persistanceEnregistrement + "\tInsertion de l'enregistrement de pulvérisation");
    }

    @Override
    void insererTerresParLot() {
        System.out.println("2. " + persistanceTerre + "\tInsertion des terres pour l'étape de pulvérisation");
    }

    @Override
    boolean estMiseAJourUniquementSoiMeme() {
        return false; // Inclut la mise à jour des descendants
    }
}

Exemple de sortie lors de l'exécution :


1. persistanceEnregistrementDemarrage	Insertion de l'enregistrement de démarrage
2. persistanceTerreDemarrage	Insertion des terres pour l'étape de démarrage
3. serviceReglesPlanPlantation	Mise à jour des règles pour le nœud courant uniquement
4. serviceEcartRegles	【Demarrage】Calcul de l'écart des règles
5. serviceReglesPlanPlantation	【Demarrage】Mise à jour du statut de l'opération

1. persistanceEnregistrementPulverisation	Insertion de l'enregistrement de pulvérisation
2. persistanceTerrePulverisation	Insertion des terres pour l'étape de pulvérisation
3. serviceInfoPlanPlantation	Mise à jour des règles pour le nœud courant et ses descendants
4. serviceEcartRegles	【Pulverisation】Calcul de l'écart des règles
5. serviceReglesPlanPlantation	【Pulverisation】Mise à jour du statut de l'opération

Cependant, cette approche laisse certains cas d'utilisation complexes, notamment pour gérer différents types de mise à jour des règles, ce qui nous amène à introduire un autre patron.

Patron Stratégie

Définition du Patron Stratégie : Il encapsule des comportements interchangeables et utilise la délégation pour choisir le comportement à appliquer au moment de l'exécution.

Pour résoudre le problème de flexibilité dans la mise à jour des règles, nous intégrons le Patron Stratégie en remplaçant la logique conditionnelle par des objets stratégie.

Intégration du Patron Stratégie

Modifions la classe abstraite pour utiliser une stratégie de mise à jour des règles.


public abstract class AbstractServiceNoeudAgricole {

    // Variable d'instance pour la stratégie de mise à jour des règles
    private RegleMiseAJour strategieRegle;

    // ... (autres services de persistance inchangés)

    /**
     * Constructeur initialisant la stratégie par défaut.
     */
    public AbstractServiceNoeudAgricole() {
        this.strategieRegle = new MiseAJourSoiMeme(); // Stratégie par défaut
    }

    /**
     * Permet de modifier dynamiquement la stratégie de mise à jour.
     */
    public void setStrategieRegle(RegleMiseAJour strategie) {
        this.strategieRegle = strategie;
    }

    /**
     * Délègue la mise à jour des règles à la stratégie courante.
     */
    public void mettreAJourReglesPlanPlantationNouvelle(String typeNœud) {
        strategieRegle.mettreAJour(typeNœud);
    }

    // La méthode modèle utilise maintenant la nouvelle méthode de délégation
    final void insererNoeudAgricoleComplet(String typeNœud) {
        insererEnregistrementActuel();
        insererTerresParLot();
        mettreAJourReglesPlanPlantationNouvelle(typeNœud); // Appel via stratégie
        calculerEcartReglesPlanPlantation(typeNœud);
        mettreAJourStatutOperationNoeud(typeNœud);
    }

    // ... (méthodes abstraites et communes restent similaires)
}

Définition de l'Interface Stratégie et ses Implémentations

D'abord, l'interface pour la stratégie de mise à jour des règles :


public interface RegleMiseAJour {
    /**
     * Met à jour les règles en fonction du type de nœud.
     * @param typeNœud Le type du nœud agricole.
     */
    void mettreAJour(String typeNœud);
}

Ensuite, plusieurs implémentations concrètes pour différents scénarios de mise à jour :


public class MiseAJourSoiMeme implements RegleMiseAJour {
    private String serviceRegles = "serviceReglesPlanPlantation";

    @Override
    public void mettreAJour(String typeNœud) {
        System.out.println("3. 【" + typeNœud + "】Mise à jour des règles pour le nœud courant (scénario de base)");
        System.out.println("(1) " + serviceRegles + "\tApplication de la règle de mise à jour simple");
    }
}

public class MiseAJourSoiMemeEtDescendants implements RegleMiseAJour {
    private String serviceInfo = "serviceInfoPlanPlantation";

    @Override
    public void mettreAJour(String typeNœud) {
        System.out.println("3. 【" + typeNœud + "】Mise à jour des règles pour le nœud courant et ses descendants");
        System.out.println("(1) " + serviceInfo + "\tPropagation de la règle aux enfants");
        System.out.println("(2) " + serviceInfo + "\tAjustement des règles pour les descendants");
    }
}

// D'autres implémentations possibles pour des cas spécifiques
public class MiseAJourSoiMemeAvecSeuil implements RegleMiseAJour {
    // Logique incluant des seuils ou conditions supplémentaires
    @Override
    public void mettreAJour(String typeNœud) {
        System.out.println("3. 【" + typeNœud + "】Mise à jour conditionnelle basée sur des seuils");
        // Implétails de logique spécifique
    }
}

Utilisation Combinée des Patrons

Avec cette intégration, les sous-classes spécifiques (comme ServiceNoeudAgricoleEtapeDemarrage et ServiceNoeudAgricoleEtapePulverisation) n'ont pas besoin d'être modifiées pour changer la stratégie de mise à jour des règles. Cela se fait dynamiquement via l'injection de la stratégie appropriée.


public class TestCombiné {
    public static void main(String[] args) {
        // Instanciation d'un service pour l'étape de démarrage
        AbstractServiceNoeudAgricole serviceDemarrage = new ServiceNoeudAgricoleEtapeDemarrage();
        // Configuration d'une stratégie de mise à jour incluant les descendants
        serviceDemarrage.setStrategieRegle(new MiseAJourSoiMemeEtDescendants());

        // Instanciation d'un service pour l'étape de pulvérisation
        AbstractServiceNoeudAgricole servicePulverisation = new ServiceNoeudAgricoleEtapePulverisation();
        // Configuration d'une stratégie de mise à jour simple
        servicePulverisation.setStrategieRegle(new MiseAJourSoiMeme());

        // Exécution des traitements complets
        serviceDemarrage.insererNoeudAgricoleComplet("Demarrage");
        System.out.println();
        servicePulverisation.insererNoeudAgricoleComplet("Pulverisation");
    }
}

Résultat possible de l'exécution, démontrant la flexibilité obtenue :


1. persistanceEnregistrementDemarrage	Insertion de l'enregistrement de démarrage
2. persistanceTerreDemarrage	Insertion des terres pour l'étape de démarrage
3. 【Demarrage】Mise à jour des règles pour le nœud courant et ses descendants
(1) serviceInfoPlanPlantation	Propagation de la règle aux enfants
(2) serviceInfoPlanPlantation	Ajustement des règles pour les descendants
4. serviceEcartRegles	【Demarrage】Calcul de l'écart des règles
5. serviceReglesPlanPlantation	【Demarrage】Mise à jour du statut de l'opération

1. persistanceEnregistrementPulverisation	Insertion de l'enregistrement de pulvérisation
2. persistanceTerrePulverisation	Insertion des terres pour l'étape de pulvérisation
3. 【Pulverisation】Mise à jour des règles pour le nœud courant (scénario de base)
(1) serviceReglesPlanPlantation	Application de la règle de mise à jour simple
4. serviceEcartRegles	【Pulverisation】Calcul de l'écart des règles
5. serviceReglesPlanPlantation	【Pulverisation】Mise à jour du statut de l'opération

Cette approche combinée illustre comment le Patron Méthode Modèle structure l'algorithme global, tandis que le Patron Stratégie injecte de la flexibilité dans les étapes variables, éliminant ainsi les conditionnels complexes et améliorant la maintenabilité du code.

Étiquettes: Java patron-méthode-modèle patron-stratégie conception-orientée-objet abstraction

Publié le 3 juillet à 08h22