From b4f0c3d2fcb20465bd86b28a8d9fd21da2a0cbca Mon Sep 17 00:00:00 2001 From: peterm85 Date: Fri, 22 Nov 2019 13:03:28 +0100 Subject: [PATCH] Add Visitor pattern --- README.md | 21 ++++++++++- .../InternationalPassenger.java | 32 +++++++++++++++++ .../NationalPassenger.java | 26 ++++++++++++++ .../airportsecuritycontrol/Passenger.java | 5 +++ .../airportsecuritycontrol/PoliceOfficer.java | 31 ++++++++++++++++ .../SecurityControlClient.java | 25 +++++++++++++ src/visitor/examples/arithmetic/Client.java | 18 ++++++++++ src/visitor/examples/arithmetic/Constant.java | 13 +++++++ .../examples/arithmetic/Expression.java | 5 +++ src/visitor/examples/arithmetic/Mult.java | 11 ++++++ src/visitor/examples/arithmetic/OpBinary.java | 9 +++++ src/visitor/examples/arithmetic/Sum.java | 11 ++++++ src/visitor/examples/arithmetic/Variable.java | 13 +++++++ .../arithmetic/VisitorExpression.java | 36 +++++++++++++++++++ 14 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 src/visitor/examples/airportsecuritycontrol/InternationalPassenger.java create mode 100644 src/visitor/examples/airportsecuritycontrol/NationalPassenger.java create mode 100644 src/visitor/examples/airportsecuritycontrol/Passenger.java create mode 100644 src/visitor/examples/airportsecuritycontrol/PoliceOfficer.java create mode 100644 src/visitor/examples/airportsecuritycontrol/SecurityControlClient.java create mode 100644 src/visitor/examples/arithmetic/Client.java create mode 100644 src/visitor/examples/arithmetic/Constant.java create mode 100644 src/visitor/examples/arithmetic/Expression.java create mode 100644 src/visitor/examples/arithmetic/Mult.java create mode 100644 src/visitor/examples/arithmetic/OpBinary.java create mode 100644 src/visitor/examples/arithmetic/Sum.java create mode 100644 src/visitor/examples/arithmetic/Variable.java create mode 100644 src/visitor/examples/arithmetic/VisitorExpression.java diff --git a/README.md b/README.md index 2d4ca66..bde9620 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Forma en que las clases u objetos interaccionan y distribuyen funcionalidades. * [Mediator](#mediator) [**O**] * [Template method](#template) [**C**] * [Iterator](#iterator) [**O**] -* [Visitor] [**O**] +* [Visitor](#visitor) [**O**] * [State] [**O**] * [Interpreter] [**C**] @@ -420,3 +420,22 @@ Primero(), Siguiente(), HayMas() y ElementoActual(). * [Notifications](https://github.com/peterm85/design-patterns/tree/master/src/iterator/examples/notifications) **Referencia:** [https://www.geeksforgeeks.org/iterator-pattern/](https://www.geeksforgeeks.org/iterator-pattern/) + +## Visitor [↑](#lista-de-patrones) + +**Propósito:** Separar el algoritmo de la estructura de un objeto. + +La idea básica es que se tiene un conjunto de clases elemento que conforman la *estructura* de un objeto. Cada una de estas clases elemento tiene un método aceptar (accept()) que recibe al objeto visitante (visitor) como argumento. El visitante es una interfaz que tiene un método visit diferente para cada clase elemento; por tanto habrá implementaciones de la interfaz visitor de la forma: visitorClase1, visitorClase2... visitorClaseN. El método accept de una clase elemento llama al método visit de su clase. + +Si hay demasiadas implementaciones de la interface visitor, se hace dificil extender. + +**Aplicación:** Usamos el patrón Visitor cuando ... +* Se desea mover la lógica operacional desde los objetos a otra clase. +* Se desea definir una operación sobre objetos de una jerarquía de clases sin modificar las clases sobre las que opera. +* Se desea representar una operación que se realiza sobre los elementos que conforman la estructura de un objeto +* Teniendo un buen número de instancias de un pequeño número de clases, se desea realizar alguna operación que involucra a todas o a la mayoría de ellas. + +**Ejemplos:** +* [Airport Security Control](https://github.com/peterm85/design-patterns/tree/master/src/visitor/examples/airportsecuritycontrol) +* [Arithmetic](https://github.com/peterm85/design-patterns/tree/master/src/visitor/examples/arithmetic) + diff --git a/src/visitor/examples/airportsecuritycontrol/InternationalPassenger.java b/src/visitor/examples/airportsecuritycontrol/InternationalPassenger.java new file mode 100644 index 0000000..941a5f4 --- /dev/null +++ b/src/visitor/examples/airportsecuritycontrol/InternationalPassenger.java @@ -0,0 +1,32 @@ +package visitor.examples.airportsecuritycontrol; + +import java.util.List; + +public class InternationalPassenger implements Passenger{ + private String passport; + private Boolean visa; + private List belongings; + + public InternationalPassenger(String passport, Boolean visa, List belongings) { + this.passport = passport; + this.visa = visa; + this.belongings = belongings; + } + + public String getPassport() { + return passport; + } + + public Boolean getVisa() { + return visa; + } + + public List getBelongings() { + return belongings; + } + + @Override + public boolean accept(PoliceOfficer visitor) { + return visitor.visit(this); + } +} diff --git a/src/visitor/examples/airportsecuritycontrol/NationalPassenger.java b/src/visitor/examples/airportsecuritycontrol/NationalPassenger.java new file mode 100644 index 0000000..5fdd313 --- /dev/null +++ b/src/visitor/examples/airportsecuritycontrol/NationalPassenger.java @@ -0,0 +1,26 @@ +package visitor.examples.airportsecuritycontrol; + +import java.util.List; + +public class NationalPassenger implements Passenger{ + private String identityDocument; + private List belongings; + + public NationalPassenger(String identityDocument, List belongings) { + this.identityDocument = identityDocument; + this.belongings = belongings; + } + + public String getIdentityDocument() { + return identityDocument; + } + + public List getBelongings() { + return belongings; + } + + @Override + public boolean accept(PoliceOfficer visitor) { + return visitor.visit(this); + } +} \ No newline at end of file diff --git a/src/visitor/examples/airportsecuritycontrol/Passenger.java b/src/visitor/examples/airportsecuritycontrol/Passenger.java new file mode 100644 index 0000000..8cf51c4 --- /dev/null +++ b/src/visitor/examples/airportsecuritycontrol/Passenger.java @@ -0,0 +1,5 @@ +package visitor.examples.airportsecuritycontrol; + +public interface Passenger { + boolean accept(PoliceOfficer visitor); +} diff --git a/src/visitor/examples/airportsecuritycontrol/PoliceOfficer.java b/src/visitor/examples/airportsecuritycontrol/PoliceOfficer.java new file mode 100644 index 0000000..cf1b594 --- /dev/null +++ b/src/visitor/examples/airportsecuritycontrol/PoliceOfficer.java @@ -0,0 +1,31 @@ +package visitor.examples.airportsecuritycontrol; + +import java.util.List; + +public class PoliceOfficer { + + public boolean visit(NationalPassenger passenger) { + boolean checked=false; + if(checkIdentification(passenger.getIdentityDocument()) && checkBelongings(passenger.getBelongings())) { + checked=true; + } + + return checked; + } + + private boolean checkIdentification(String id) { + return id!=null && !id.equals(""); + } + + private boolean checkBelongings(List belongings) { + return !belongings.contains("Liquids"); + } + + public boolean visit(InternationalPassenger passenger) { + boolean checked=false; + if(checkIdentification(passenger.getPassport()) && checkBelongings(passenger.getBelongings()) && passenger.getVisa()) { + checked=true; + } + return checked; + } +} diff --git a/src/visitor/examples/airportsecuritycontrol/SecurityControlClient.java b/src/visitor/examples/airportsecuritycontrol/SecurityControlClient.java new file mode 100644 index 0000000..af7d17d --- /dev/null +++ b/src/visitor/examples/airportsecuritycontrol/SecurityControlClient.java @@ -0,0 +1,25 @@ +package visitor.examples.airportsecuritycontrol; + +import java.util.Arrays; +import java.util.Collections; + +public class SecurityControlClient { + + public static void main(String[] args) { + Passenger[] passengers = new Passenger[] {new NationalPassenger("45874005H", Arrays.asList("Coins","Bag","Sun glasses")), + new NationalPassenger(null, Collections.EMPTY_LIST), + new InternationalPassenger("4A4585BC", true, Arrays.asList("Cap","False beard","Gun")), + new InternationalPassenger("11AB8564", false, Arrays.asList("Suitcase","Coat")), + new InternationalPassenger("269LZF74", false, Arrays.asList("Liquids"))}; + + PoliceOfficer officer = new PoliceOfficer(); + + for(Passenger p: passengers) { + if(p.accept(officer)) { + System.out.println("Access granted"); + }else { + System.out.println("Access NOT granted"); + } + } + } +} diff --git a/src/visitor/examples/arithmetic/Client.java b/src/visitor/examples/arithmetic/Client.java new file mode 100644 index 0000000..18aec88 --- /dev/null +++ b/src/visitor/examples/arithmetic/Client.java @@ -0,0 +1,18 @@ +package visitor.examples.arithmetic; + +public class Client { + + public static void main(String argv[]) { + // Construcción de una expresión (a+5)*(b+1) + Expression expresion = new Mult( new Sum( new Variable("a"), + new Constant(5) ), + new Sum( new Variable("b"), + new Constant(1) )); + + VisitorExpression expr = new VisitorExpression(); + expresion.aceptar(expr); + + // Visualizacion de resultados + System.out.println("Resultado: " + expr.obtenerResultado()); + } +} diff --git a/src/visitor/examples/arithmetic/Constant.java b/src/visitor/examples/arithmetic/Constant.java new file mode 100644 index 0000000..0832f65 --- /dev/null +++ b/src/visitor/examples/arithmetic/Constant.java @@ -0,0 +1,13 @@ +package visitor.examples.arithmetic; + +public class Constant extends Expression { + int _valor; + + public Constant(int valor) { + _valor = valor; + } + + public void aceptar(VisitorExpression v) { + v.visitConstant(this); + } +} \ No newline at end of file diff --git a/src/visitor/examples/arithmetic/Expression.java b/src/visitor/examples/arithmetic/Expression.java new file mode 100644 index 0000000..41b7b28 --- /dev/null +++ b/src/visitor/examples/arithmetic/Expression.java @@ -0,0 +1,5 @@ +package visitor.examples.arithmetic; + +public abstract class Expression { + abstract public void aceptar(VisitorExpression v); +} diff --git a/src/visitor/examples/arithmetic/Mult.java b/src/visitor/examples/arithmetic/Mult.java new file mode 100644 index 0000000..bfa82b5 --- /dev/null +++ b/src/visitor/examples/arithmetic/Mult.java @@ -0,0 +1,11 @@ +package visitor.examples.arithmetic; + +public class Mult extends OpBinary { + public Mult(Expression izq, Expression der) { + super(izq, der); + } + + public void aceptar(VisitorExpression v) { + v.visitMult(this); + } +} diff --git a/src/visitor/examples/arithmetic/OpBinary.java b/src/visitor/examples/arithmetic/OpBinary.java new file mode 100644 index 0000000..c863277 --- /dev/null +++ b/src/visitor/examples/arithmetic/OpBinary.java @@ -0,0 +1,9 @@ +package visitor.examples.arithmetic; + +public abstract class OpBinary extends Expression { + Expression _izq, _der; + + public OpBinary(Expression izq, Expression der) { + _izq = izq; _der = der; + } +} diff --git a/src/visitor/examples/arithmetic/Sum.java b/src/visitor/examples/arithmetic/Sum.java new file mode 100644 index 0000000..ee6342e --- /dev/null +++ b/src/visitor/examples/arithmetic/Sum.java @@ -0,0 +1,11 @@ +package visitor.examples.arithmetic; + +public class Sum extends OpBinary { + public Sum(Expression izq, Expression der) { + super(izq, der); + } + + public void aceptar(VisitorExpression v) { + v.visitSum(this); + } +} diff --git a/src/visitor/examples/arithmetic/Variable.java b/src/visitor/examples/arithmetic/Variable.java new file mode 100644 index 0000000..3488241 --- /dev/null +++ b/src/visitor/examples/arithmetic/Variable.java @@ -0,0 +1,13 @@ +package visitor.examples.arithmetic; + +public class Variable extends Expression { + String _variable; + + public Variable(String variable) { + _variable = variable; + } + + public void aceptar(VisitorExpression v) { + v.visitVariable(this); + } +} \ No newline at end of file diff --git a/src/visitor/examples/arithmetic/VisitorExpression.java b/src/visitor/examples/arithmetic/VisitorExpression.java new file mode 100644 index 0000000..f0dfa6e --- /dev/null +++ b/src/visitor/examples/arithmetic/VisitorExpression.java @@ -0,0 +1,36 @@ +package visitor.examples.arithmetic; + +public class VisitorExpression { + + private String _resultado; + + public void visitVariable(Variable v) { + _resultado = v._variable; + } + + public void visitConstant(Constant c) { + _resultado = String.valueOf(c._valor); + } + + private void visitOpBinary(OpBinary op, String pOperacion) { + op._izq.aceptar(this); + String pIzq = obtenerResultado(); + + op._der.aceptar(this); + String pDer = obtenerResultado(); + + _resultado = "(" + pIzq + pOperacion + pDer + ")"; + } + + public void visitSum(Sum s) { + visitOpBinary(s, "+"); + } + + public void visitMult(Mult m) { + visitOpBinary(m, "*"); + } + + public String obtenerResultado() { + return _resultado; + } +} \ No newline at end of file