Définition: résume certaines opérations qui agissent sur chaque élément d'une certaine structure de données. Il peut définir de nouvelles opérations qui agissent sur ces éléments sans modifier la structure des données.
Type: modèle de comportement
Diagramme de classe:
exemple:
Par exemple, pensez à ajouter différents types de marchandises au panier et lorsque vous cliquez sur la caisse, il calcule les frais à payer pour toutes les différentes marchandises. Maintenant, la logique de calcul est de calculer les prix de ces différents types de marchandises. Ou en d'autres termes, nous transférons cette logique vers une autre classe via le mode visiteur. Implémentons cet exemple de modèle de visiteur.
Pour implémenter le modèle des visiteurs, la première chose à faire est de créer une classe qui peut être ajoutée au panier pour représenter différents types d'articles (éléments d'objets).
ItelsElement.javapackage com.journaldev.design.visitor; interface publique ItemElement {public int accepte (shoppingcartVisitor Visitor);}Notez que la méthode d'acceptation accepte le visiteur comme un paramètre. Bien sûr, il existe d'autres moyens de spécifier des produits détaillés ici, mais pour la simplicité, il n'est pas nécessaire de considérer trop de détails ici, se concentrant uniquement sur le mode visiteur.
Créez maintenant des cours d'entités pour différents produits.
Livre.java
package com.journalv.design.visitor; le livre de classe publique implémente itemberElement {private int prix; String privé isbnnumber; Livre public (int Cost, String isbn) {this.price = Cost; this.isbnnumber = isbn; } public int getPrice () {prix de retour; } public String getisbnnumber () {return isBnnumber; } @Override public int accepte (shoppingcartVisitor Visitor) {return visitor.visit (this); }}Fruit.java
package com.journalv.design.visitor; public class fruit implémente itelement {private int prixPerkg; poids int privé; nom de chaîne privé; Fruit public (int pricekg, int wt, string nm) {this.pricePerkg = prixkg; this.weight = wt; this.name = nm; } public int getPricepperkg () {return pricePerkg; } public int getweight () {return poids; } public String getName () {return this.name; } @Override public int accepte (shoppingcartVisitor Visitor) {return visitor.visit (this); }} Notez que la mise en œuvre de la méthode Accept () se trouve dans la classe d'entité, qui appelle la méthode Visit () du visiteur pour passer l'objet de classe actuel comme son propre paramètre.
Ici, la méthode Visit () utilisée pour différents types de marchandises sera mise en œuvre dans la classe d'entité de l'interface des visiteurs.
Shoppingcartvisitor.java
Package com.journaldev.design.visitor; Interface publique ShoppingCartVisitor {int Visit (livre de livres); Int Visit (fruits fruits);}L'interface des visiteurs sera désormais implémentée et la logique du calcul de ses propres dépenses pour chaque produit.
ShoppingcartVisitorImp.java
Package com.journaldev.design.visitor; classe publique ShoppingCartVisitorImpl implémente ShoppingCartVisitor {@Override public int Visit (Book Book) {int Cost = 0; // appliquer 5 $ de remise si le prix du livre est supérieur à 50 if (book.getprice ()> 50) {cost = book.getprice () - 5; } else Cost = book.getprice (); System.out.println ("Book Isbn ::" + book.getisbnnumber () + "Cost =" + Cost); coût de retour; } @Override public Int Visit (fruit fruit) {int Cost = fruit.getPricePerkg () * fruit.getweight (); System.out.println (fruit.getName () + "Cost =" + Cost); coût de retour; }}Voyons maintenant comment l'utiliser dans le programme.
Shoppingcartclient.java
Package com.journaldev.design.visitor; public class shoppingcartClient {public static void main (String [] args) {itelsElement [] items = new Itements [] {nouveau livre (20, "1234"), nouveau livre (100, "5678"), nouveau fruit (10, 2, "banana"), nouveau fruit (5, 5, "Apple")};; int total = calculPrice (éléments); System.out.println ("Total Cost =" + Total); } private static int calculPrice (itelsElement [] items) {shoppingcartVisitor Visitor = new ShoppingCartVisitorImpl (); int sum = 0; pour (itemElement item: items) {sum = sum + item.accept (visiteur); } RETOUR SUM; }}Lors de l'exécution du programme ci-dessus, nous obtenons la sortie suivante.
Livre ISBN :: 1234 COST = 20BOOK ISBN :: 5678 COST = 95BANANA COST = 20APPLE COST = 25 TOTAL COST = 160
Veuillez noter que la mise en œuvre ici semble être la même que la méthode Accept () pour tous les produits, mais elle peut également être différente. Par exemple, si le produit est vide, il peut effectuer des vérifications logiques et n'appelle plus la méthode Visit ().
Avantages du mode visiteur:
Respectez le principe de responsabilité unique: dans tout scénario où le mode visiteur est applicable, les opérations qui doivent être encapsulées chez le visiteur dans la classe d'éléments doivent être des opérations qui ont peu à voir avec la classe d'éléments elle-même et sont volatiles. D'une part, l'utilisation du mode visiteur est conforme au principe de responsabilité unique, et d'autre part, car les opérations encapsulées sont généralement volatiles, lorsque des changements se produisent, l'expansion de la partie changeante peut être réalisée sans modifier la classe d'élément elle-même.
Bonne évolutivité: les classes d'éléments peuvent étendre différentes opérations en acceptant différents visiteurs.
Scénarios applicables pour le mode visiteur:
S'il existe des opérations dans un objet qui ne sont pas liées à l'objet (ou faiblement lié) et afin d'éviter que ces opérations contaminent l'objet, vous pouvez utiliser le mode visiteur pour encapsuler ces opérations dans le visiteur.
S'il existe des opérations similaires dans un groupe d'objets, afin d'éviter un grand nombre de code en double, ces opérations en double peuvent également être encapsulées dans le visiteur.
Cependant, le mode visiteur n'est pas si parfait, et il a également des défauts mortels: l'ajout de nouvelles classes d'éléments est plus difficile. Grâce au code du modèle des visiteurs, nous pouvons voir que dans la classe des visiteurs, chaque classe d'élément a sa méthode de traitement correspondante. C'est-à-dire que chaque classe d'éléments doit être ajoutée pour modifier la classe des visiteurs (y compris également la sous-classe ou la classe d'implémentation de la classe Visitor), ce qui est assez gênant à modifier. C'est-à-dire que lorsque le nombre de classes d'éléments est incertain, le mode visiteur doit être utilisé avec prudence. Par conséquent, le mode visiteur est plus adapté pour refactoriser les fonctions existantes. Par exemple, si les fonctions de base d'un projet ont été déterminées, les données des classes d'éléments ont été essentiellement déterminées et ne changent pas. Tout ce qui changera, ce sont les opérations pertinentes au sein de ces éléments. À l'heure actuelle, nous pouvons utiliser le mode visiteur pour refacter le code d'origine, afin que les fonctions d'origine puissent être modifiées sans modifier chaque classe d'élément.
Résumer:
En tant que GOF, l'auteur de Design Pattern, décrit le mode visiteur: dans la plupart des cas, vous devez utiliser le mode visiteur, mais une fois que vous en avez besoin, vous en avez vraiment besoin. Bien sûr, ce n'est que pour les vrais gros gars. En réalité (au moins dans l'environnement dans lequel je suis), beaucoup de gens sont souvent accro aux modèles de conception. Lors de l'utilisation d'un modèle de conception, ils ne considèrent jamais sérieusement si le modèle qu'ils utilisent convient à ce scénario, mais veulent souvent montrer leur capacité à contrôler la conception orientée objet. Si vous avez cette mentalité lors de la programmation, vous abusez souvent du modèle de conception. Par conséquent, lors de l'apprentissage des modèles de conception, vous devez comprendre l'applicabilité des modèles. Il est nécessaire d'utiliser un modèle parce que vous comprenez ses avantages, pas pour utiliser un modèle parce que vous comprenez ses inconvénients; Plutôt que d'utiliser un modèle parce que vous ne comprenez pas ses inconvénients, pas pour utiliser un modèle parce que vous ne comprenez pas ses avantages.