10.23.07
Patrón de Diseño: Data Access Object (DAO) + Data Transfer Object (DTO)
Y como no, sigo dándole vueltas a mejorar el acceso y la protección de los datos.
Antes de empezar a haceros un breve resumen de lo que es un DAO y un DTO os dejo primero unos links donde podréis verlos en marcha de forma mucho más concreta.
http://en.wikipedia.org/wiki/Data_Access_Object
http://en.wikipedia.org/wiki/Data_Transfer_Object
http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
El chiste del DAO es que nos provee de una forma totalmente abstracta de acceso a datos. Es decir, puedo acceder a mi modelo de datos, pero únicamente a través del conjunto de métodos que me brinda un DAO. Si tengo un DAO para coches, por ejemplo CocheDAO, en él deberé tener definido por ejemplo un método Count() que me retornará el total de coches que tengo en mi base de datos. No sé cómo está implementado, ni qué base de datos utiliza (si es que accede a una base de datos), lo único que sé es que resuelve mi problema.
Por lo tanto, desde la parte del Controlador de mi aplicación, puedo acceder a mi Modelo utilizando el patrón de diseño que ofrece DAO, de forma totalmente transparente. Esto por ejemplo nos llevaría a pensar que nuestro CocheDAO podría contener otros métodos, como el método Delete (que borraría un coche de la base de datos), Update (que actualizaría los datos de un coche), GetCochesByMarca (que a partir de una marcha retornaría los coches de la marca que hay en la base de datos), etc.
Todo esto suena en principio a lo mismo que sería tener una clase llamada Coche llena de métodos static a los cuales llamaría cuando fuera necesario. Esto, pues claro, resuelve el problema de tener todo el acceso a la tabla Coche centralizado, olé, bien, somos ordenados, pero DAO va mucho más allá. ¿Cómo resolveríais el problema de devolver un listado de coches a través de vuestra clase con métodos static? Pues a lo mejor vuestro método GetCoches() retorna un dataset rellenado con los coches, o un datareader/recordset, o una lista separada por comas, o una estructura xml, o un array… Pero los DAO incluyen otro concepto que es del los DTO. Los DTO son un tipo de objetos que sirven únicamente para transportar datos. Por ejemplo, el objeto de transferencia de datos de un coche podría ser un CocheDTO (o CocheBean para los javeros). Entonces, DAO, lo que devuelve es una lista genérica de CocheBean, o tal vez un CocheBean si estamos buscando información de un solo coche. Para que os hagáis una idea, un CocheBean contiene únicamente propiedades de un coche como por ejemplo Marca, NumeroPuertas, Matrícula, etc. El DAO, tras una petición del Controlador, rellena un DTO o un conjunto de ellos, y lo devuelve al Controlador.
¿Y todo este lío para qué? Pues muy sencillo, si vuestro controlador ataca al modelo utilizando DAO y DTO estáis consiguiendo 100% la separación entre el Controlador y el Modelo. Ante cualquier cambio que se diera en la forma de acceder a los datos, pongamos por ejemplo que a partir de ahora en lugar de sacar los coches de una tabla coches se hace de un servicio web que retorna coches, vuestro modelo no se va a enterar, ya que lo que le va a seguir llegando van a ser siempre CocheBean. Conseguís un impacto cero patatero en vuestro Controlador (y en la Vista claro, pero eso ya lo habíamos conseguido separando la Vista del Controlador).
Y aún más, si cada uno de vuestros DAO lo preparáis para seguir el patrón Singleton, tendréis siempre una única instancia de la clase CocheDAO en memoria, por lo que aunque tengáis 200 usuarios tirando de dicho DAO tendréis una única copia en memoria, con el ahorro que esto supone. Esto no ocurre por ejemplo si usáis static en todos los métodos de vuestras clases de acceso a datos (y os recuerdo que en un proyecto mediano el número de métodos que llegan a acumularse para acceso a datos suele ser bastante grande).
¿Un ejemplo de código? Venga, vale, aceptamos barco, imaginaos que atacamos a una hipotética clase CocheDAO:
// GetInstance pide la instancia de la clase mediante el Singleton, CocheDAO tiene su constructor en modo privado.
CocheBean coche = CocheDAO.GetInstance().GetCocheByMatricula(‘IB-3234-ZX’);
// ahora tenemos un CocheBean, si no es nulo es que ha llegado bien, cogemos sus datos
if (coche != null)
{
txtMatricula.Text = coche.Matricula;
txtMarca.Text = coche.Marca;
txtNumeroPuertas.Text = coche.NumeroPuertas;
}
¿Y qué ocurre en el Controlador si cambiamos el nombre del campo matrícula en la tabla coches? Pues nada, ni se entera.
Para finalizar os añado un link a un rar que he preparado con un DAO y un DTO preparados, que acceden a una hipotética tabla de Coches. Fijaros en el DAO lo que hace el Singleton, que además de forzar la utilización del método GetInstance, utiliza exclusión mútua para evitar que se tenga más de una instancia del DAO en el caso de no haberse creado aún la instancia y dos usuarios accedieran al mismo tiempo al método GetInstance. El método GetCoche retorna un CocheBean, pero el método GetCoches lo que hace es retornar un lista genérica de CocheBean. Veréis además que CocheDAO hereda de BaseDAO, todos los DAOS deberían heredar de allí ya que BaseDAO les ofrece entre otras cosas la conexión a la base de datos y una serie de métodos comunes que pueden utilizar (BaseDAO lo he dejado algo básico sólo para que se entienda conceptualmente qué es lo que se supone que debe hacer). También tenéis la definición de CocheBean. Por último, veréis que existe un archivo llamado Excepciones donde se tipifican las excepciones que puede generar un DAO, una de las buenas prácticas de las que ya hemos hablado en otros artículos.
Os contaría además que DAO puede implementarse junto a DTO, pero además utilizando el modelo de Factoría, pero esto, lo dejaremos para más adelante.
Ejemplo DAO (esta vez os lo preparo en VB.NET, por variar un poco).
¿Interesante?
Saludos.
Miguel.
Goyo Granja said,
November 16, 2007 at 1:00 pm
Hola Miguel,
Me parace muy interesante el artículo pero hay una cosa que no entiendo y puede que tenga más que ver con el patrón singleton que con el acceso a datos. No entiendo porqué utilizas el singleton en lugar de métodos estáticos. Se supone que un método estático es compartido por la apliación y no se crea una instancia de dicho método cada vez que sea utilizado ¿no es así?.
Saludos.
Miguel said,
November 17, 2007 at 6:43 pm
Hola Goyo,
En primer lugar, si utilizas métodos estáticos ten en cuenta que un hijo de un DAO no podrá sobreescribir el método y eso hace perder potencia a tu definición. Imagínate el caso de que creas una clase de pruebas que herede de tu DAO y sobreescriba la definición de alguno de los métodos para hacer como te digo ciertas pruebas… si son static no vas a poder hacerlo. Estás perdiendo la orientación a objetos.
En segundo lugar, no tengo muy claro que si declaras todos tus métodos estáticos puedas llevar a cabo una factoría de DAOs. Y eso volvería a ser otra vez perder potencia.
Saludos.
Miguel.
Goyo Granja said,
November 19, 2007 at 10:07 pm
Hola Miguel,
Bien, utilizando métodos estáticos no podemos sobreescribirlos en herencia y por tanto el código es menos flexible y tampoco podemos utilizar una factoria.
Salvando este inconveniente y si no cecesitamos herencia, el rendimiento sería similar utilizando métodos estáticos y el singletón
¿O realmente hay diferencias de rendimiento cuando hay muchos usuarios (ocupación de memoria, etc.) en un caso y otro?
Gracias por tu respuesta.
Saludos,
Goyo.
Miguel said,
November 19, 2007 at 11:50 pm
Hola de nuevo,
La verdad es que en cuanto rendimiento desconozco totalmente si el uso de una u otra solución te podrá aportar una mejora de peso.
El único problema que conozco al respecto lo podrías tener si utilizas el singleton sin crear la zona de exclusión mútua al comprobar si se ha hecho instancia de la clase DAO (en el método getInstance).
Siento no poder aclararte más dudas respecto a la diferencia de rendimiento.
Saludos!
Miguel.
Goyo Granja said,
November 21, 2007 at 9:51 am
Gracias por tu ayuda y enhorabuena por tus artículos.
Saludos,
Goyo.
rsavo said,
February 1, 2008 at 3:39 am
Es genial este patrón, facilita mucho el desarrollo de un sistema por capas, lo estoy usando en un proyecto actual y vale la pena el esfuerzo extra a cambio de una mayor portabilidad y organización.
Miguel said,
February 9, 2008 at 10:21 am
La verdad es que ayuda a dejar la capa de acceso a datos niquelada. Fácilmente mantenible, totalmente estructurada, y lo más importante, eres capaz de sacar esa pieza y substituirla sin que el resto de capas ni tan siquiera se enteren del cambio.
shirley said,
June 10, 2008 at 1:12 am
Muy buen material
Saludos
Miguel said,
June 10, 2008 at 2:22 pm
Gracias Shirley,
Cualquier tipo de aportación, corrección o mejora al artículo que pueda aumentar su valor, es más que bienvenida.
Un saludo.
Miguel.
Cris said,
June 25, 2008 at 6:56 pm
Hola Miguel,
Gracias por explicar de una manera clara este tema, por si alguien no sabe que es el patrón Singleton, ahi les va una breve explicación.
El patrón singleton se implementa creando en nuestra clase un método que crea una instancia del objeto sólo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con atributos como protegido o privado).
Miguel said,
June 25, 2008 at 8:41 pm
Gracias por la aportación Cris.
Saludos.
Miguel.
Jeff said,
September 2, 2008 at 4:36 am
Hola Miguel,
Muchas gracias por tu paciencia al explicar este tipo de temas que son de gran ayuda.
Saludos.
Elizabeth said,
June 11, 2009 at 2:44 pm
Hola, muy buena la explicacion, clara y precisa, me quedo con una buena base para empezar el nuevo proyecto en el que estoy, gracias.
Miguel said,
June 12, 2009 at 4:37 pm
Ánimo con vuestro trabajo, cualquier aportación será bienvenida
Voy a intentar preparar una segunda parte a futuro de este artículo, que veo que a muchos os ha resultado interesante.
Saludos.
Rodolfo said,
September 9, 2009 at 2:41 am
En hora buena Miguel, la verdad que que tu articulo es de muchisima ayuda .
Muchas Gracias, y espero que sigas desaznando nuestras intrigas de progrmación.
Un abrazo.
Saludos.
leidy said,
September 24, 2009 at 4:36 am
hola Miguel. me parece muy interensate este articulo, ya que soy apenas una estudiante de desarrollo de software(me lo dejaste muy muy claro), y q bn poderlo implementar.
El ejemplo DAO esta disponible en c#?
Txumari said,
December 3, 2009 at 6:41 pm
Me soluciona alguna dudas, creo que es hora de comenzar a implementar y encontrarme de frente con esto.
Voy a ver que mas articulos interesantes tienes por el blog
Manu said,
February 24, 2010 at 7:06 pm
Muy buen resumen !!! muy didactica tu explicacion.
gracias Miguel
Manu said,
February 24, 2010 at 7:11 pm
Hola miguel tendras el ejemplito en Java ???