Definição: encapsula certas operações que atuam em cada elemento em uma determinada estrutura de dados. Ele pode definir novas operações que agem sobre esses elementos sem alterar a estrutura de dados.
Tipo: padrão comportamental
Diagrama de classe:
exemplo:
Por exemplo, pense em adicionar diferentes tipos de mercadorias ao carrinho e, ao clicar na compra, ele calcula as taxas a serem pagas por todas as diferentes mercadorias. Agora, a lógica de cálculo é calcular os preços desses diferentes tipos de mercadorias. Ou, em outras palavras, transferimos essa lógica para outra classe através do modo de visitante. Vamos implementar este exemplo de padrão de visitante.
Para implementar o padrão do visitante, a primeira coisa a fazer é criar uma classe que possa ser adicionada ao carrinho de compras para representar diferentes tipos de itens (itemElements).
ItemElement.javapackage com.journalDev.design.visitor; interface pública ItemElement {public int aceit (visitante de compras (visitante de compras);}Observe que o método aceita aceita o visitante como um parâmetro. Obviamente, existem outras maneiras de especificar produtos detalhados aqui, mas, por simplicidade, não há necessidade de considerar muitos detalhes aqui, concentrando -se apenas no modo de visitante.
Agora crie algumas classes de entidade para diferentes produtos.
Book.java
pacote com.journalDev.design.visitor; public class Book implementa o itemElement {private int price; String privada isbnNumber; Public Book (int custo, string isbn) {this.price = custo; this.isbnNumber = ISBN; } public int getPrice () {Return Price; } public string getisbnNumber () {return isbnNumber; } @Override public int Accept (Visitante ShoppCartVisitor) {return visitor.visit (this); }}Fruit.java
pacote com.journalDev.design.visitor; classe pública implementa a fruta itemElement {private int priceperkg; peso privado int; nome de string privado; public frut (int pricekg, int wt, string nm) {this.pricePerkg = pricekg; this.weight = wt; this.name = nm; } public int getPricePerkg () {return priceperkg; } public int getWeight () {return Weight; } public string getName () {return this.name; } @Override public int Accept (Visitante ShoppCartVisitor) {return visitor.visit (this); }} Observe que a implementação do método aceit () está na classe de entidade, que chama o método visitante () do visitante () para passar no objeto atual de classe como seu próprio parâmetro.
Aqui, o método visit () usado para diferentes tipos de mercadorias será implementado na classe de entidade da interface do visitante.
Shoppingcartvisitor.java
pacote com.journalDev.design.visitor; interface pública ShoppingCartVisitor {int visit (livro); int visit (fruta);}A interface do visitante agora será implementada e a lógica de calcular suas próprias despesas para cada produto.
ShoppCartVisitorImpl.java
pacote com.journalDev.design.visitor; public class shoppingcartvisitorImpl implementa ShoppingCartVisitor {@Override public int visit (livro) {int custo = 0; // Aplique 5 $ desconto se o preço do livro for maior que 50 if (book.getprice ()> 50) {Cost = book.getPrice ()-5; } else custo = book.getprice (); System.out.println ("livro isbn ::"+book.getisbnNumber ()+"Cost ="+custo); custo de retorno; } @Override public int visit (frutas) {int cost = fruit.getPricePerkg ()*fruit.getweight (); System.out.println (fruit.getName () + "Cost =" + Cost); custo de retorno; }}Agora vamos ver como usá -lo no programa.
ShoppingcartClient.java
pacote com.journalDev.design.visitor; public classe shoppingcartClient {public static void main (string [] args) {itemElement [] itens = novo itemElement [] {New Book (20, "1234"), novo livro (100, "5678"), "New Fruit (10, 2," Banana "),"), New Fruit (5678 ")," 5678, 5, 5, "»}; int total = calcularprice (itens); System.out.println ("Total Cost ="+Total); } private static int calcularprice (itemElement [] itens) {shoppingCartVisitor visitante = new ShoppingCartVisitorImpl (); int sum = 0; para (itemElement Item: itens) {soma = soma + item.accept (visitante); } retornar soma; }}Ao executar o programa acima, obtemos a seguinte saída.
Livro ISBN :: 1234 Custo = 20Book ISBN :: 5678 Custo = 95banana Cost = 20 Apple Cost = 25Total Cost = 160
Observe que a implementação aqui parece ser a mesma que o método aceit () para todos os produtos, mas também pode ser diferente. Por exemplo, se o produto estiver vazio, ele poderá executar verificações lógicas e não chama mais o método visit ().
Vantagens do modo de visitante:
Cumprir o princípio da responsabilidade única: em qualquer cenário em que o modo de visitante seja aplicável, as operações que precisam ser encapsuladas no visitante na classe de elementos devem ser operações que têm pouco a ver com a própria classe de elementos e são voláteis. Por um lado, o uso do modo de visitante está em conformidade com o princípio da responsabilidade única e, por outro lado, porque as operações encapsuladas são geralmente voláteis, quando ocorrem mudanças, a expansão da parte em mudança pode ser alcançada sem alterar a própria classe de elementos.
Boa escalabilidade: as classes de elementos podem estender diferentes operações, aceitando diferentes visitantes.
Cenários aplicáveis para o modo de visitante:
Se houver algumas operações em um objeto que não estiverem relacionadas ao objeto (ou fracamente relacionado) e, para evitar essas operações que contaminam o objeto, você poderá usar o modo de visitante para encapsular essas operações no visitante.
Se houver operações semelhantes em um grupo de objetos, a fim de evitar um grande número de código duplicado, essas operações duplicadas também podem ser encapsuladas no visitante.
No entanto, o modo de visitante não é tão perfeito e também possui falhas fatais: adicionar novas classes de elementos é mais difícil. Através do código do padrão do visitante, podemos ver que, na classe de visitantes, cada classe de elemento possui seu método de processamento correspondente. Ou seja, cada classe de elemento precisa ser adicionada para modificar a classe de visitantes (incluindo também a classe de subclasse ou implementação da classe de visitantes), o que é bastante problemático para modificar. Ou seja, quando o número de classes de elemento é incerto, o modo de visitante deve ser usado com cautela. Portanto, o modo de visitante é mais adequado para refatorar as funções existentes. Por exemplo, se as funções básicas de um projeto foram determinadas, os dados das classes de elementos foram basicamente determinados e não serão alterados. Tudo o que mudará são as operações relevantes dentro desses elementos. No momento, podemos usar o modo de visitante para refatorar o código original, para que as funções originais possam ser modificadas sem modificar cada classe de elemento.
Resumir:
Como GoF, o autor do padrão de design, descreve o modo de visitante: na maioria dos casos, você precisa usar o modo de visitante, mas depois de precisar, você realmente precisa. Claro que isso é apenas para os caras grandes. Na realidade (pelo menos no ambiente em que estou), muitas pessoas geralmente são viciadas em padrões de design. Ao usar um padrão de design, eles nunca consideram seriamente se o padrão que eles estão usando é adequado para esse cenário, mas muitas vezes apenas querem mostrar sua capacidade de controlar o design orientado a objetos. Se você tem essa mentalidade ao programar, muitas vezes abusa do padrão de design. Portanto, ao aprender padrões de design, você deve entender a aplicabilidade dos padrões. É necessário usar um padrão porque você entende suas vantagens, não para usar um padrão porque entende suas desvantagens; Em vez de usar um padrão porque você não entende suas desvantagens, não para usar um padrão porque não entende suas vantagens.