Modèle de visiteur (type de comportement)

Dans le modèle de visiteur , nous utilisons une classe visiteur, qui modifie l'algorithme d'exécution de la classe d'élément. De cette façon, l'algorithme d'exécution de l'élément peut changer à mesure que le visiteur change. Ce type de modèle de conception est un modèle comportemental. Selon le modèle, l'objet élément a accepté l'objet visiteur afin que l'objet visiteur puisse gérer les opérations sur l'objet élément.

Utiliser la scène

  1. La structure d'objet est relativement stable, mais il est souvent nécessaire de définir de nouvelles opérations sur cette structure d'objet.
  2. Vous devez effectuer de nombreuses opérations différentes et indépendantes sur les objets dans une structure d'objet, et vous devez éviter que ces opérations ne "polluent" les classes de ces objets, et vous ne voulez pas modifier ces classes lors de l'ajout de nouvelles opérations.

Introduction au rôle

  • Visitor: interface ou classe abstraite qui définit le comportement d'accès à chaque élément. Ses paramètres sont les éléments auxquels on accède. Le nombre de ses méthodes est théoriquement le même que le nombre d'éléments. Par conséquent, le modèle de visiteur requiert la Le type doit être stable. Si vous ajoutez et supprimez fréquemment des classes d'éléments, cela entraînera inévitablement des modifications fréquentes de l'interface de visiteur. Si cela se produit, cela signifie que le mode visiteur ne convient pas.
  • ConcreteVisitor: visiteur spécifique, il doit donner le comportement spécifique généré lors de la visite de chaque classe d'élément.
  • Élément: interface d'élément ou classe abstraite, qui définit une méthode pour accepter le visiteur (accept), ce qui signifie que chaque élément doit être accessible par le visiteur.
  • ElementA, ElementB: une classe d'élément spécifique, qui fournit une implémentation spécifique pour recevoir l'accès, et cette implémentation spécifique consiste généralement à utiliser la méthode fournie par le visiteur pour accéder à la classe d'élément.
  • ObjectStructure: structure d'objet mentionnée dans la définition. La structure d'objet est une expression abstraite, qui gère en interne la collection d'éléments et peut itérer ces éléments pour fournir un accès aux visiteurs.

Atteindre

La fin, le CEO et CTO commencer à évaluer le rendement au travail de l'année, les employés répartis ingénieurs et gestionnaires, CTO préoccupés par le nombre de nouveaux ingénieurs quantité de code produit, les gestionnaires, CEO craint que les ingénieurs KPI KPI et les gestionnaires en
raison du PDG et directeur technique pour Différents employés ont des préoccupations différentes, ce qui nécessite des traitements différents pour différents types d'employés. Le mode visiteur peut désormais être utile.

La première étape consiste à définir l'interface et la classe d'élément

La classe Personnel définit les informations de base sur les employés et une méthode d'acceptation. La méthode d'acceptation représente l'acceptation des visites des visiteurs et est implémentée par des sous-classes. Le visiteur est une interface, passant dans différentes classes d'implémentation pour accéder à différentes données . Regardons les codes des ingénieurs et des managers:

package visitor.demo;

import java.util.Random;

// 员工基类
public abstract class Staff {

    public String name;
    public int kpi;// 员工KPI

    public Staff(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }
    // 核心方法,接受Visitor的访问
    public abstract void accept(Visitor visitor);
}
package visitor.demo;

import java.util.Random;

// 工程师
public class Engineer extends Staff {

    public Engineer(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 工程师一年的代码数量
    public int getCodeLines() {
        return new Random().nextInt(10 * 10000);
    }
}
package visitor.demo;

import java.util.Random;

// 经理
public class Manager extends Staff {

    public Manager(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 一年做的产品数量
    public int getProducts() {
        return new Random().nextInt(10);
    }
}

La deuxième étape consiste à définir l'interface du visiteur et des visiteurs spécifiques

Tout d'abord, une interface visiteur est définie. Cette interface a deux fonctions de visite, et les paramètres sont respectivement Ingénieur et Manager. C'est-à-dire que deux méthodes différentes seront appelées pour l'accès d'Ingénieur et Manager, afin de réaliser des traitements et différenciations différents. La classe d'implémentation spécifique est CEOVisitor, classe CTOVisitor, le code spécifique est le suivant:

package visitor.demo;

public interface Visitor {

    // 访问工程师类型
    void visit(Engineer engineer);

    // 访问经理类型
    void visit(Manager manager);
}

 

package visitor.demo;

// CEO访问者
public class CEOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi);
    }
}

Parmi les visiteurs du PDG, le PDG prête attention aux KPI de l'ingénieur et des KPI du manager et les traite séparément via deux méthodes de visiteur. Si vous n'utilisez pas le mode Visiteur et n'utilisez qu'une méthode de visite pour le traitement, vous devez évaluer cette méthode de visite, puis les traiter séparément. Le code est à peu près le suivant: 

public class ReportUtil {
    public void visit(Staff staff) {
        if (staff instanceof Manager) {
            Manager manager = (Manager) staff;
            System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi +
                    ", 新产品数量: " + manager.getProducts());
        } else if (staff instanceof Engineer) {
            Engineer engineer = (Engineer) staff;
            System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi);
        }
    }
}

Cela conduit à l' imbrication de la logique if-else et de la coercition de type, qui est difficile à étendre et à maintenir . Lorsqu'il existe de nombreux types, ce ReportUtil sera très compliqué. En utilisant le mode Visiteur, différentes paires de types d'éléments sont traitées via la même fonction pour rendre la structure plus claire et plus flexible.

La méthode de visite surchargée effectuera différentes opérations sur l'élément, et en injectant différents visiteurs, l'implémentation spécifique du visiteur peut être remplacée , ce qui rend l'opération sur l'élément plus flexible et plus extensible, tout en éliminant le type Conversion, if-else et autres codes "laids".

Ajoutez une autre classe de visiteurs CTO:

package visitor.demo;

public class CTOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师: " + engineer.name + ", 代码行数: " + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理: " + manager.name + ", 产品数量: " + manager.getProducts());
    }
}

La troisième étape consiste à créer une structure d'objet qui gère la collection d'éléments en interne et itère ces éléments pour fournir un accès aux visiteurs.

Ajoutez ces employés à une classe de rapport d'activité, les dirigeants d'entreprise peuvent afficher les performances de tous les employés via la méthode showReport de la classe de rapport, le code spécifique est le suivant:

package visitor.demo;

import java.util.LinkedList;
import java.util.List;

// 员工业务报表类
public class BusinessReport {

    private List<Staff> mStaffs = new LinkedList();

    public BusinessReport() {
        mStaffs.add(new Manager("经理-A"));
        mStaffs.add(new Engineer("工程师-A"));
        mStaffs.add(new Engineer("工程师-B"));
        mStaffs.add(new Engineer("工程师-C"));
        mStaffs.add(new Manager("经理-B"));
        mStaffs.add(new Engineer("工程师-D"));
    }

    /**
     * 为访问者展示报表
     * @param visitor 公司高层,如CEO、CTO
     */
    public void showReport(Visitor visitor) {
        for (Staff staff : mStaffs) {
            staff.accept(visitor);
        }
    }
}

Commencez le test ci-dessous

package visitor.demo;

public class Client {

    public static void main(String[] args) {
        // 构建报表
        BusinessReport report = new BusinessReport();
        System.out.println("=========== CEO看报表 ===========");
        report.showReport(new CEOVisitor());
        System.out.println("=========== CTO看报表 ===========");
        report.showReport(new CTOVisitor());
    }
}
=========== CEO看报表 ===========
经理: 经理-A, KPI: 0
工程师: 工程师-A, KPI: 4
工程师: 工程师-B, KPI: 6
工程师: 工程师-C, KPI: 8
经理: 经理-B, KPI: 9
工程师: 工程师-D, KPI: 2
=========== CTO看报表 ===========
经理: 经理-A, 产品数量: 9
工程师: 工程师-A, 代码行数: 65794
工程师: 工程师-B, 代码行数: 43012
工程师: 工程师-C, 代码行数: 81633
经理: 经理-B, 产品数量: 6
工程师: 工程师-D, 代码行数: 94267

Dans l'exemple ci-dessus, le personnel joue le rôle d'élément, tandis que l'ingénieur et le gestionnaire sont tous deux ConcreteElement; CEOVisitor et CTOVisitor sont des objets Visitor spécifiques; et BusinessReport est ObjectStructure; Client est le code client.
Le plus grand avantage du modèle de visiteur est qu'il est très facile d'ajouter des visiteurs. Nous pouvons voir dans le code que si vous voulez ajouter un visiteur, tant qu'une nouvelle classe d'interface de visiteur est implémentée, l'effet de la séparation des objets de données et des opérations de données est obtenu. Si le modèle de visiteur n'est pas pratique et que vous ne souhaitez pas effectuer différentes opérations sur différents éléments, vous devez utiliser la conversion if-else et le type, ce qui rend la mise à niveau et la maintenance du code difficiles.

Résumé

Nous devons évaluer s'il convient d'utiliser le modèle de visiteur en fonction de la situation spécifique, par exemple, si notre structure d'objet est suffisamment stable, si nous devons définir de nouvelles opérations fréquemment et si le modèle de visiteur peut optimiser notre code, plutôt que de faire changer notre code. Pour être plus compliqué.

  • Avantages du mode visiteur.

    1. Séparation des responsabilités de chaque rôle, conformément au principe de la responsabilité unique
      . Comme le montrent le diagramme de classes UML et l'exemple ci-dessus, Visitor, ConcreteVisitor, Element, ObjectStructure ont une seule responsabilité et chacun a sa propre responsabilité.
    2. Possède une excellente évolutivité
      Si vous devez ajouter de nouveaux visiteurs, vous pouvez rapidement développer en ajoutant la classe d'implémentation ConcreteVisitor.
    3. Découplage de la structure des données et des opérations qui agissent sur la structure, afin que l'ensemble des opérations puisse changer indépendamment Découplage des
      attributs des employés (structure des données) et des visiteurs du PDG et des CTO (opérations des données).
    4. Flexibilité
  • Inconvénients du modèle visiteur.

    1. Les éléments spécifiques publient les détails aux visiteurs, ce qui viole le principe Dimit. Le
      PDG et le CTO doivent appeler les méthodes des employés spécifiques.
    2. Les modifications d'éléments spécifiques entraînent des coûts de modification importants. Lors du
      changement des attributs d'un employé, plusieurs visiteurs doivent les modifier.
    3. Il viole le principe de l'inversion de la dépendance et s'appuie sur des cours concrets pour obtenir un "traitement différent". Puisque les
      méthodes abstraites de visite des visiteurs ne se sont pas appuyées sur les méthodes concrètes d'employés spécifiques.
Publié 138 articles originaux · loué 34 · 150 000 vues

Je suppose que tu aimes

Origine blog.csdn.net/bbj12345678/article/details/105379374
conseillé
Classement