Coupling

Acoplamiento

Si uso una llamada a Utils.calculaClave() desde mi clase y Utils cambia su función a Utils.calculaClave(boolean complejo), tendré que cambiar mi código y adaptarlo.

Si accedo a un atributo de otra clase y esa otra clase hace el atributo privado para protegerlo de cambios, tendré que cambiar mi código y adaptarlo.

              
  public interface Visitable{
    public void accept(Visitor visitor);
  }
  
  public interface Visitor{
    public void visit(Visitable v);
    
    //Visitable2 y OtroVisitable implementan Visitable
    public void visit(Visitable2 v2);
    public void visit(OtroVisitable v3);
  }
              
            
              
  public class Visitable2 {
    public void accept(Visitor visitor) {
      //Si no sabemos quién es, pasamos de él
    }
    
    //Amigo implementa Visitor
    public void accept(Amigo visitor) {
      //A este sí le dejo visitarme
      visitor.visit(this);
    }
  }  
  
  public class OtroVisitable {
    public void accept(Visitor visitor) {
      //A mi en cambio me da igual
      visitor.visit(this);
    }
  }
              
            
              
    for(Visitable v : visitables) {
      //cada visitable decide si acepta o no
      //y si acepta, llama al "visit" del visitor
      v.accept(visitor);
    }
              
            

Decisión por parte del Visitable

Si añadimos nuevos Visitors, hay que modificar Visitable

Acoplamiento fuerte

Útil para recorrer elementos de forma genérica

              
  //Todas nuestras estrategias hacen "do"
  public interface IStrategy {
  
    //Esta función puede ser cualquier cosa
    public String do();
  }
              
            
              
  public class EstrategiaSimple implements IStrategy {
    public String do() {
      return "Y ya está. Hecho.";
    }
  }
  
 public class EstrategiaComplicada implements IStrategy {
    public String do() {
      StringBuilder sb = new StringBuilder("Y");
      sb.append(" ");
      sb.append("ya está");
      sb.append(". ");
      sb.append("Hecho.");
      return b.toString();
    }
  }
              
            
              
  public class EstrategiaRara implements IStrategy {
    public String do() {
      StringBuilder sb = new StringBuilder("Pues");
      sb.append(" yo");
      sb.append(" devuelvo");
      sb.append(" otra");
      sb.append(" cosa.");
      return b.toString();
    }
  }
              
            
              
  //Clase super simple que ejecuta una estrategia según
  //qué sea lo mejor ¡¡en tiempo real!!
  public class Demo {
    public static void main(String[] args) {
      //Obtenemos la mejor estrategia
      IStrategy strategy = getBestStrategy(args);
        
      //No necesitamos saber la estrategia concreta para ejecutarla aquí
      System.out.println(strategy.do());
    }
  }
              
            
              
  //Clase super simple que ejecuta una estrategia según
  //qué sea lo mejor ¡¡en tiempo real!!
  public class Demo {
    public static void main(String[] args) {
      //Obtenemos la mejor estrategia
      IStrategy strategy = getBestStrategy(args);
        
      //No necesitamos saber la estrategia concreta para ejecutarla aquí
      System.out.println(strategy.do());
    }
  }
              
            

Pero getBestStrategy,

¿lo implementamos nosotras?

Seguimos altamente acopladas

              
  public class Demo {
    public static void main(String[] args) {
      //el constructor asigna una estrategia por defecto
      Vendedor v = new Vendedor();
      
      //pasan cosas en tu código
      //en algún momento, alguien llama a algo como
      v.setStrategy(new EstrategiaOptimaParaEsteCaso());
      
      //pasan más cosas
      //quizás la situación cambia y alguien llama otra vez    
      v.setStrategy(new OtraEstrategia());
      
      //y finalmente, necesitamos ejecutar la estrategia
      v.getStrategy().do();  
    }
  }
              
            
              
  public class Demo {
    public static void main(String[] args) {
      //el constructor asigna una estrategia por defecto
      Vendedor v = new Vendedor();
      
      //pasan cosas en tu código
      //en algún momento, alguien llama a algo como
      v.setStrategy(new EstrategiaOptimaParaEsteCaso());
      
      //pasan más cosas
      //quizás la situación cambia y alguien llama otra vez    
      v.setStrategy(new OtraEstrategia());
      
      //y finalmente, necesitamos ejecutar la estrategia
      v.getStrategy().do();  
    }
  }
              
            

¿Qué tiene esto que ver con el visitor?

¿Qué tiene esto que ver con el visitor?

              
  public class Casa implements Visitable {
    public void accept(Visitor visitor) {
      //Esto es spam, ni le abro
    }
    public void accept(Amigo visitor) {
      visitor.visit(this);
    }
  }  
  
  public class Empresa implements Visitable {
    public void accept(Visitor visitor) {
      //Sí a todo
      visitor.visit(this);
    }
  }
              
            
              

  public class Demo {
    public static void main(String[] args) {
      List<Visitables> edificios;
      Visitor vendedora = new Vendedora();
      
      for(Visitable v : edificios) {
        //cada visitable decide si acepta o no
        //y si acepta, llama al "visit" del visitor
        //como visitor mi estrategia está definida
        v.accept(visitor);
      }
    }
  }
              
            
              
  public class EstrategiaAmable implements IStrategy {
    public void visit(Visitable v) {
      
    }
  }
  
 public class SugerAgresiva implements IStrategy {
    public void visit(Visitable v) {
     
    }
  }
              
            
                public class Demo {
    public static void main(String[] args) {
      List<Visitables> edificios;
      Vendedora vendedora = new Vendedora(new DefaultStrategy());
      if(esUnBarrioResidencial()) {
        vendedora.setStrategy(new EstrategiaAmable());
      }
      if(estamosDeRebajas()) {
        vendedora.setStrategy(new SuperAgresiva());
      }
      for(Visitable v : edificios) {
        //El visitable no puede bloquearme
        //soy yo quien decido hasta dónde llego
        vendedora.getStrategy().visit(v);
      }
    }
  }
              
            

¿Hacemos un triple salto mortal?

              
  public class Demo {
    public static void main(String[] args) {
      List<Visitables> edificios;
      Visitor vendedora = new Vendedora();
      
      
      
      for(Visitable v : edificios) {
        //cada visitable decide si acepta o no
        //y si acepta, llama al "visit" de la vendedora
        //como visitor mi estrategia está definida
        v.accept(vendedora);
      }
    }
  }
              
            
              
  public class Demo {
    public static void main(String[] args) {
      List<Visitables> edificios;
      Visitor vendedora = new Vendedora();
      if(estamosDeRebajas()) {
        vendedora.setStrategy(new SuperAgresiva());
      }
      for(Visitable v : edificios) {
        //cada visitable decide si acepta o no
        //y si acepta, llama al "visit" de la vendedora
        //como vendedora mi estrategia es en tiempo real
        v.accept(vendedora);
      }
    }
  }