Lo patrones de diseño, sirven para adaptar tu sistema o algunas de sus funciones al mismo, el objetivo del mismo es: otorgar mayor facilidad y comodidad al desarrollador y en este caso el patrón Bridge, no es excluido.
BRIDGE (Puente)
Sirve para desacoplar una abstracción de la implementación. Lo que trae opr beneficio: Se puede ocupar sin ningun problema y sin procupación que pueda cambiar en tiempo de ejecución. Además existe la capacidad de esconder los detalles de la implementación a los clientes.
Una aplicación popular de Bridge, es mejorar la extensibilidad, lo que quiere decir que se puede extender las jerarquías de la clase de abstracción y la clase que implementa independientemente.
A continuación se muestra un ejemplo del uso y aplicación del mismo.
Elementos:
- ICrud
Define una interfaz abstracta para mantener una referencia a un objeto de tipo IPuente.
- IPuente
Define la interfaz para la implementación de clases. Ésta interfaz no se tiene que corresponder exactamente con la interfaz de ICrud; de hecho, las dos interfaces pueden ser bastante diferente. Típicamente la interfaz IPuente provee sólo las operaciones primitivas y ICrud define operaciones de alto nivel basadas en éstas primitivas.
- ImplementaPuente
Extiende la interfaz definida por ICrud.
Elementos que son necesarios para la aplicación del patrón:
- Base de datos (SQL)
- Proyecto (C#)
Cabe mencionar que además de haber logrado aplicar el patrón Bridge en nuestro proyecto, ha sido montado sobre el popular patrón MVC.

Aplicación:
Crear, consultar, editar y eliminar un empleado con los siguientes datos:
- Nombre
- Apellido Paterno
- Apellido Materno
- Fecha de Nacimiento
- Sexo
Y generar una inserción a una base de datos diferente que resultará como una bitacora de los cambios y registros que se hacen de los mismos.
BD ‘patronDB’ ( Empleado)
Contiene general del proyecto

BD ‘bitacoraPatronDB’ (bitacora)
Contiene el historial del proyecto.

Implementando el patrón Bridge.
1.- Pantalla: frmEmpleadoManager.

- Permite visualizar todos los registros de la base de datos, además de poder editar, eliminar, buscar y abrir el formulario con un botón, para hacer una inserción de registro.
2.- Pantalla: frmEmpleadoPrincipal.

- Permite hacer una inserción de registro.
- Permite modificar o editar un registro.
Una vez que ya se tienen éstas dos pantallas, lo siguiente es saber:
¿Cómo se logra el objetivo del patrón?
A continuación se muestra la Interfaz de operaciones que funge como anfitrión; Por supuesto hablamos de ICrud.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sergio.Patron.Control.Ctrl.CtrlGenericas.CtrlResultado;
namespace Sergio.Patron.Control.Ctrl.CtrlGenericas.Crud
{
public interface ICrud
{
Resultado insertar(Object _obj);
Resultado eliminar(Object _obj);
Resultado modificar(Object _obj);
Object consultaSimple(Object _obj);
List<Object> consultaGlobal(Object _obj);
}
}
Por lo consiguiente se hace presente el patrón en la Interfaz IPuente, que no es más que la copia de la interfaz original, puesto que funcionará como puente y tienen que concordar los métodos u operaciones que se vayan a realizar a lo largo de la ejecución de tu programa.
using Sergio.Patron.Control.Ctrl.CtrlGenericas.CtrlResultado;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Sergio.Patron.Control.Ctrl.CtrlGenericas.Crud
{
//Copia excata de los métodos que utiliza la Interfaz de ICrud
public interface IPuente
{
Resultado insertar(Object _obj);
Resultado eliminar(Object _obj);
Resultado modificar(Object _obj);
Object consultaSimple(Object _obj);
List<Object> consultaGlobal(Object _obj);
}
}
Ahora hacemos la implementación del puente de Interfaz a Interfaz en una clase que lleva por nombre (ImplementaPuente), es decir:
- ICrud -> IPuente
using Sergio.Patron.Control.Ctrl.CtrlGenericas.Crud;
using Sergio.Patron.Control.Ctrl.CtrlGenericas.CtrlResultado;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Sergio.Patron.Control.Ctrl.Implementa
{
public class ImplementaPuente : IPuente
{
private ICrud icrud;
private Resultado resultado = new Resultado();
//Constructor que recibe el nombre de la Clase a donde se están haciendo las operaciones
// y establece la dirección.
public ImplementaPuente(ICrud _icrud)
{
//Se asigna el valor recibido a la instancia privada de la clase.
this.icrud = _icrud;
}
public CtrlGenericas.CtrlResultado.Resultado insertar(object _obj)
{
try
{
//icrud, ya contiene el nombre del control, ejemplo: CtrlCrudEmpleadoBitacora = icrud y ahora //se envía al método de la inserción, la cual apunta a una nueva tabla.
icrud.insertar(_obj);
this.resultado.Accion = true;
return this.resultado;
}
catch (Exception _e)
{
this.resultado.Informacion = _e.Message;
return this.resultado;
}
}
public CtrlGenericas.CtrlResultado.Resultado eliminar(object _obj)
{
throw new NotImplementedException();
}
public CtrlGenericas.CtrlResultado.Resultado modificar(object _obj)
{
try
{
icrud.modificar(_obj);
this.resultado.Accion = true;
return this.resultado;
}
catch (Exception _e)
{
this.resultado.Informacion = _e.Message;
return this.resultado;
}
}
public object consultaSimple(object _obj)
{
throw new NotImplementedException();
}
public List<object> consultaGlobal(object _obj)
{
throw new NotImplementedException();
}
}
}
Antes de que la implementemos en el formulario, es necesario hacer el crud donde se implemente la Interfaz de puente. (Cabe mencionar: Con el puente se cumple el objetivo de preparar las acciones de un CRUD y preparar la inserción a la Base de Datos y a la tabla de Bitácora).
using Sergio.Patron.Control.Ctrl.CtrlGenericas;
using Sergio.Patron.Control.Ctrl.CtrlGenericas.Crud;
using Sergio.Patron.Control.Ctrl.CtrlGenericas.CtrlConexion;
using Sergio.Patron.Control.Ctrl.CtrlGenericas.CtrlResultado;
using Sergio.Patron.Modelo.Entidades;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
namespace Sergio.Patron.Control.Ctrl.CrtlCrudEntidad
{
public class CtrlCrudEmpleadoBitacora : ICrud
{
private Resultado resultado = new Resultado();
private CtrlConectar ctrlConexion = new CtrlConectar();
//SqlConnection conexion = new SqlConnection(«server=LAPTOP-KFMEPDE7; database=bitacoraPatronDB; Integrated Security = true»);
string sentenciaSql = String.Empty;
#region ICrud
public Resultado insertar(Object _object)
{
try
{
// cadena: Es la variable que utiliza para generar una bitácora.
String cadena = (String)_object;
sentenciaSql = «insert into bitacora (historial) VALUES (‘» + cadena + «‘);»;
SqlCommand cmd = new SqlCommand(sentenciaSql, ctrlConexion.abrirConexion());
cmd.ExecuteNonQuery();
this.resultado.Accion = true;
return this.resultado;
}
catch (Exception _e)
{
this.resultado.Informacion = _e.Message;
return this.resultado;
}
finally
{
ctrlConexion.cerrarConexion();
}
}
public Resultado modificar(object _object)
{
try
{
//Castea el objeto que llega a la operación y la convierte a un objeto de tipo ‘Empleado’
Empleado empleado = (Empleado)_object;
sentenciaSql = «UPDATE Empleado SET strNombre = ‘» + empleado.StrNombre + «‘, strAPaterno = ‘» + empleado.StrAPaterno +
«‘, strAMaterno = ‘» + empleado.StrAMaterno + «‘, dteFechaNacimiento = ‘» + empleado.DteFechaNacimiento.ToShortDateString() + «‘, idCatSexo = » + empleado.IdCatSexo.Id
+ » WHERE id = » + empleado.Id;
SqlCommand cmd = new SqlCommand(sentenciaSql, ctrlConexion.abrirConexion());
cmd.ExecuteNonQuery();
this.resultado.Accion = true;
return this.resultado;
}
catch (Exception _e)
{
this.resultado.Informacion = _e.Message;
return this.resultado;
}
finally
{
//IMPORTANTE: No olvidar cerrar conexión a BD
ctrlConexion.cerrarConexion();
}
}
public Resultado eliminar(object _object)
{
try
{
Empleado _empleado = (Empleado)_object;
sentenciaSql = «DELETE FROM Empleado «
+ » WHERE id = » + _empleado.Id;
SqlCommand cmd = new SqlCommand(sentenciaSql, ctrlConexion.abrirConexion());
cmd.ExecuteNonQuery();
this.resultado.Accion = true;
return resultado;
}
catch (Exception _e)
{
this.resultado.Informacion = _e.Message;
return this.resultado;
}
finally
{
ctrlConexion.cerrarConexion();
}
}
public object consultaSimple(object _object)
{
throw new NotImplementedException();
}
public List<object> consultaGlobal(object _object)
{
string refMensaje = String.Empty;
try
{
string sentenciaSql = string.Empty;
Empleado _empleado = (Empleado)_object;
sentenciaSql = «SELECT _e.id, _e.strNombre, _e.strAPaterno, _e.strAMaterno, _e.dteFechaNacimiento, _c.id, _c.strValor » +
» FROM Empleado _e join CatSexo _c on _e.idCatSexo = _c.id where _e.idCatSexo = » + _empleado.IdCatSexo.Id + » and _e.strNombre like ‘%» + _empleado.StrNombre + «%'»;
List<Object> listaObjeto = new List<Object>();
SqlCommand cmd = new SqlCommand(sentenciaSql, ctrlConexion.abrirConexion());
SqlDataReader lector = cmd.ExecuteReader();
while (lector.Read())
{
Empleado empleado = new Empleado();
CatSexo catSexo = new CatSexo();
empleado.Id = int.Parse(lector[0].ToString());
empleado.StrNombre = lector[1].ToString();
empleado.StrAPaterno = lector[2].ToString();
empleado.StrAMaterno = lector[3].ToString();
empleado.DteFechaNacimiento = (DateTime)lector[4];
catSexo.Id = int.Parse(lector[5].ToString());
catSexo.StrValor = lector[6].ToString();
empleado.IdCatSexo = catSexo;
listaObjeto.Add(empleado);
}
return listaObjeto;
}
catch (Exception _e)
{
this.resultado.Informacion = _e.Message;
return null;
}
finally
{
ctrlConexion.cerrarConexion();
}
}
#endregion
}
}
Y por útlimo, creamos y generamos la implementación del puente en el formulario, en el botón de Aceptar en frmEmpleadoManager
private void btnAceptar_Click(object sender, EventArgs e)
{
try
{
//Llenado inicial de la variable ‘Cadena’ que se enviará
Cadena = «El registro: «
+ this.entidadGeneral.StrNombre + » «
+ this.entidadGeneral.StrAPaterno + » «
+ this.entidadGeneral.StrAMaterno + «, «
+ this.entidadGeneral.IdCatSexo + «. FechaN:»
+ this.entidadGeneral.DteFechaNacimiento;
this.entidadGeneral.StrNombre=this.mtbNombre.Text.Trim();
this.entidadGeneral.StrAPaterno = this.mtbAPaterno.Text.Trim();
this.entidadGeneral.StrAMaterno = this.mtbAMaterno.Text.Trim();
this.entidadGeneral.DteFechaNacimiento = this.dtpFechaNacimiento.Value;
this.entidadGeneral.IdCatSexo = (CatSexo)this.cmbSexo.SelectedItem;
CtrlValidaEmpleado ctrlValidaEmpleado = new CtrlValidaEmpleado();
Resultado resultado = ctrlValidaEmpleado.validaEmpleado(entidadGeneral, listaControl);
if (!resultado.Accion)
{
MessageBox.Show(resultado.Informacion, Resources.mensajeSistema, MessageBoxButtons.OK, MessageBoxIcon.Error);
System.Windows.Forms.Control control = this.listaControl[resultado.Control];
control.Focus();
}
else
{
// Se crea la instancia de la Interfaz IPuente que hará el recorrido por el número de objetos enviados
IPuente[] ipuentes = new IPuente[2];
// Posición 0: Se envían las acciones que se generan en la inserción principal (Empleado).
ipuentes[0] = new ImplementaPuente(new CtrlCrudEmpleado());
// Posición 1: Se envían las acciones que se generan en la inserción secundaria (EmpleadoBitacora).
ipuentes[1] = new ImplementaPuente(new CtrlCrudEmpleadoBitacora());
CtrlCrudEmpleado ctrlCrudEmpleado = new CtrlCrudEmpleado();
if (this.editar)
{
//Concatenación de la cadena que de inserción a bitacora.
Cadena += «–Cambió por: : («
+ this.mtbNombre.Text.Trim() + » «
+ this.mtbAPaterno.Text.Trim() + » «
+ this.mtbAMaterno.Text.Trim() + «, FechaN: «
+ this.dtpFechaNacimiento.Value + «, «
+ this.cmbSexo.SelectedItem + «) el día: » + this.fechaHoy;
//Posición 0: MODIFICACIÓN demandada por el IF, CtrlCrudEmpleado.
if (ipuentes[0].modificar(entidadGeneral).Accion )
{
//Posición 1: Inserción de cadena en la clase: CtrlCrudEmpleadoBitacora.
ipuentes[1].insertar(Cadena);
MessageBox.Show(«Se a editado correctamente el registro», Resources.mensajeSistema,
MessageBoxButtons.OK, MessageBoxIcon.Information);
this.accionPantalla = true;
this.Close();
}
else
{
MessageBox.Show(«Error al guardar la información», Resources.mensajeSistema,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
//Concatenación de los valores a la cadena para insertar en caso de ser: Inserción en el
// objeto principal (Empleado)
Cadena += «—Ha sido registrado el día: «+ this.fechaHoy+».»;
//Posición 0: INSERCIÓN demandada por el IF, CtrlCrudEmpleado.
if (ipuentes[0].insertar(entidadGeneral).Accion )
{
//Posición 1: Inserción de cadena en la clase: CtrlCrudEmpleadoBitacora.
ipuentes[1].insertar(Cadena);
MessageBox.Show(«Se a guardado correctamente el registro»,
Resources.mensajeSistema, MessageBoxButtons.OK, MessageBoxIcon.Information);
this.accionPantalla = true;
this.Close();
}
else
{
MessageBox.Show(«Error al guardar la información»,
Resources.mensajeSistema, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
catch (Exception _e)
{
MessageBox.Show(_e.Message, Resources.mensajeSistema, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Para terminar, cabe mencionar que el objetivo ha sido logrado mediante la implementación del patrón solicitado (BRIDGE). Se espera que haya quedado claro el uso y la implementación de cada una de las partes que componen al patrón.
Link de descarga (Proyecto completo).
https://drive.google.com/drive/folders/16rsWA6eL9eO_K4OK6bJ9zhEzMLj6s85s?usp=sharing
