Bridge (padrón de deseño)

O padrón Ponte, tamén coñecido como Bridge, é un padrón, pertencente á categoría de padróns estruturais, empregado na enxeñaría do software. Con el pretendese separar unha abstracción da súa implementación, desta forma poderanse empregar implementacións alternativas.

O padrón Ponte pode ser moi útil cando as implementacións varian a miúdo. Nese caso, as características da programación orientada a obxectos, tórnanse moi útiles, podendo facer cambios no código cun mínimo coñecemento previo do programa.

 Obxectivos 
 Desacoplar unha abstracción da súa implementación de forma que ambas poidan variar independentemente.
 Illamento mais aló da encapsulación.

 Aplicabilidade 
Podemos empregar o padrón Ponte cando:
 Queremos evitar unha ligazón permanente entre a abstracción e a súa implementación, podendo ser debido a que a implementación debe ser seleccionada ou cambiada en tempo de execución.
 Tanto as abstracción coma as súas implementación deben ser extensibles por medio de subclases. Neste caso, o padrón Ponte permite combinar abstracción e implementación diferentes e estendelas independentemente.
 Os cambios na implementación dunha abstracción non deben impactar nos clientes,o seu código non ten que ser recompilado.
 Queremos ocultar a implementación dunha abstracción completamente ós clientes.
 Deséxase compartir unha implementación entre múltiples obxectos, e isto é ocultado ós clientes.

 Participantes 
 Abstracción (Abstraction): define a clase interface. Mantén unha referencia ó obxecto implementador.
 Abstracción refinada (RefinedAbstraction): estende e implementa a interface Abtracción.
 Implementador (Implementor): define a interface para as clases implementación. Esta interface non ten que corresponderse exactamente coa interface de Abstraction, as das interfaces poden ser bastante diferentes. Tipicamente a interface Implementor prové só de operacións primitivas, e Abstraction define operacións de alto nivel baseadas nestas primitivas.
 Implementador Concreto (ConcreteImplementor): as clases implementadas

 Consecuencias 
 Desacoplamento do obxecto interface e implementación: unha implementación non é limitada permanentemente a unha interface. A implementación dunha abstracción pode configurarse en tempo de execución. Ademais, un obxecto, ten a posibilidade de cambiar a súa implementación en tempo de execución. Desacopla Abstraction e Implementor tamén elimina as dependencias sobre a implementación en tempo de compilación. Cambiar unha clase de implementación non require recompilar a clase Abstraction nin os seus clientes. Esta propiedade é esencial cando hai que asegurar a compatibilidade binaria entre diferentes versións dunha biblioteca de clases, fomentando as capas, que nos leven a un nivel mellor estruturado.
 Mellorar a estensibilidade: Pódese estender as xerarquías de abstracción e implementación de forma independente.

 Estrutura 
O cliente non quere lidiar cos detalles dependentes da plataforma. O padrón Ponte encapsula estas complexidades tras unha capa abstracta.

Ponte enfatiza identificar e desacoplar a abstracción de interface da abstracción da implementación.
px 500|centro

 Implementación 
 Só un Implementador: en situación onde existe só unha implementación, non é preciso crear una clase Implementor abstracta, sendo este, un caso especial do padrón no que hai unha relación un-a-un entre Abstraction e Implementor. Non obstante, esta separación é moi útil cando un cambio na implementación dunha clase non debe afectar os seus clientes.
 Implemementador: Sendo esta unha das principais diferenzas có padrón estratexia, se a abstracción coñece a xerarquía de implementadores pode crear o implementador no construtor, podendo decidir cal instanciar dependendo dos parámetros do construtor. O inconveniente ven dado pola dependencia da xerarquía, se aparece un novo teremos que modificar a abstracción.

Outra aproximación é delegar noutro obxecto (singleton), este encargarase de proporciona o implementador concreto da abstracción.

 Compartir implementadores.
 Empregando herdanza múltiple.

 Ponte con outros padróns 
 Adaptador fai que as cousas funcionen despois de ser deseñadas, Ponte fai que as cousas funcionen antes de ser deseñadas.
 Ponte é deseñado para permitir que a abstracción e a implementación varíen de forma independente.Adaptador é deseñado para que clases non relacionadas traballen xuntas.
 Estado, Estratexia, Ponte (e algúns casos de Adaptador) teñen solucións estruturais semellantes. Diferéncianse na intención, resolven diferentes problemas.A estrutura de Estado e de Ponte é idéntica (excepto que Ponte admite xerarquías de herdanza envolventes, mentres que Estado só permite unha). Os dous padróns usan a mesma estrutura para resolver diferentes problemas: Estado permite cambiar o comportamento dun obxecto o cambiar o seu estado, mentres que Ponte pretende desacoplar a abstracción da súa implementación, podendo variar estas dúas de forma independente.
 Se a clase interface delega a creación a clase implementación, entón o deseño usualmente emprega o padrón Fábrica Abstracta para crear os obxectos implementación.
 Ponte semella o padrón adaptador , pero mentres que o padrón Adaptador intenta que as interfaces dunha ou máis clases sexa a mesma que para unha clase particular, Ponte está deseñado para separar as clases interfaces da súa implementación, desta forma poder variar e substituír as súas implementacions sen cambiar o código cliente.

 Exemplo 
/*
 * Memoria que permite o intercambio dos datos almacenados na mesma
 * 
 */

class MemoriaIntercambio extends Memoria{

  public MemoriaIntercambio(ImplementacionMemoria memoria){
    super(memoria);
  }

  // Intercambia o dato almacenado na posición i, co almacenado na posición j
  public void intercambiar(Integer i, Integer j){
    String aux = super.obtener(i);
    super.guardar(i, super.obtener(j));
    super.guardar(j, aux);

  }
}

/*
 * Memoria que unicamente permite obter e gardar datos.
 * 
 */

class Memoria {

  public Memoria(ImplementacionMemoria memoria){
    _imp = memoria;
  }

  //Obtén o dato da posición i
  public String obtener(Integer i) { 
    return _imp.obtener(i);
  }

  // Garda o dato na posición i
  public void guardar(Integer i, String dato){ 
    _imp.guardar(i, dato);
  }

  // atributo privado coa implementación específica da memoria
  private ImplementacionMemoria _imp;
}

/**
 * Clase Main do exemplo do padrón Ponte (Bridge)
 *
 */
public class main {

	/**
	 * @param args
	 */
	static public void main(String argv[]) {

		ImplementacionMemoria mhash = new ImplementacionHash();
		ImplementacionMemoria mvector = new ImplementacionVector();

		Memoria m = new Memoria(mhash);
		MemoriaIntercambio mi = new MemoriaIntercambio(mvector);

		m.guardar(0, "0xfa21");
		m.guardar(1, "0x8732");
		m.guardar(2, "0x329f");

		mi.guardar(0, "0xfa21");
		mi.guardar(1, "0x8732");
		mi.intercambiar(0, 1);

		System.out.println(m.obtener(1));

		System.out.println(mi.obtener(0));
	}

}

/*
 * Implementación de Memoria usando Vector.
 * 
 */

import java.util.Vector;

class ImplementacionVector implements ImplementacionMemoria {

  public ImplementacionVector() {
    _mem = new Vector<String>();
  }
  //Obtén o dato da posición i
  public String obtener(Integer i) {
    return _mem.get(i.intValue());
  }

  // Garda o dato na posición i
  public void guardar(Integer i, String dato) {
	if (_mem.size() <= i){
		while (_mem.size() <= i){
			_mem.add("nil");
		}
	}
    _mem.set(i.intValue(), dato);
  }

  private Vector<String> _mem;
}

/*
 * Interface que debe de ser implementada, polas implementacións específicas da memoria
 * 
 */

interface ImplementacionMemoria {

  //Obtén o dato da posición i
  public String obtener(Integer i);

  // Guarda el dato en la posición i
  public void guardar(Integer i, String dato);

}

/*
 * Implementación de Memoria usando HashMap.
 * 
 */

import java.util.HashMap;

class ImplementacionHash implements ImplementacionMemoria {

  public ImplementacionHash() {
    _mem = new HashMap<Integer, String>();
  }
  //Obtén o dato da posición i
  public String obtener(Integer i) {
    return _mem.get(i);
  }

  // Garda o dato na posición i
  public void guardar(Integer i, String dato) { 
    _mem.put(i, dato);
  }

  private HashMap<Integer, String> _mem;
}

Categoría:Padróns de deseño