El tema de este artículo - porqué la aplicación del mapping ORM en Java (se habla de cualquier tipo de ORM: JPA, Hibernate, etc) no es un
buen ejemplo de la programación orientada a objetos y que podemos hacer para mejorar esta situación.
Sabemos que cuando se habla del mapping ORM, hablamos de varios
frameworks JPA que permiten acceder a una base de datos (BD) relacional. Los frameworks
JPA nos permiten de ser más productivos en el entorno de Java, donde trabajamos
con los objetos.
Como ejemplo, consideramos una típica clase de
unidad en Hibernate:
@Entity
@table (name = "Users")
public class User {
@id @GeneratedValue
@Column (name = "id")
Identificación
del private int;
@Column (name =
"name")
private String nombre;
Usuario público () {}
public int getId () {
Identificación
del retorno;
}
setId pública vacío (int id) {
this.id
= id;
}
Public String getName () {
Nombre
del retorno;
}
pública setName void (String
nombre) {
esto. name =
nombre;
}
}
Se ve que tenemos una tabla SQL llamada "Users"
con 2 columnas y la clase User representa esta tabla en el dominio de Java.
En verdad este código me parece horrible desde
punto de vista de la programación orientada a objetos y ahora os explico
porque.
Tenemos un problema.
El problema principal es que esta clase no actúa como
un objeto en el sentido de la POO, sino simplemente como un contenedor de los datos.
Debajo he puesto un gráfico, se ve que nuestro
programa principal llama la clase 'User' y le asigna un nombre de
"Jeff". Luego el programa llama una sesión Hibernate, le pasa
nuestro usuario para actualizar la base de datos. En este sentido nuestro
objeto no hace nada por si mismo, sirve simplemente como un contenedor de los datos.
Hibernate hace lo siguiente: abre una transacción,
recupera "usuario" con el antiguo nombre de la BD, cambia su nombre por
el nuevo al final actualiza la base de
datos.
La vuelta a la programación por procedimientos?
Como he dicho antes, nuestro objeto “User” no se comporta como un objeto en el sentido de POO, sino simplemente un contenedor. El paradigma de POO se inventó precisamente
para evitar los problemas relacionados con la programación por procedimientos. En la época de los lenguajes como C o Assembler tuvimos una secuencia de
comandas que se ejecutaron una detrás de otra y estas comandas manejaban a los
datos. Este método ha funcionado bien con los pequeños programas con poco código. Cuando la cantidad de código aumenta, este paradigma deja de ser eficaz:
se hace difícil de gestionar el código y mantenerlo.
Por esta razón fue inventada la programación
orientada a objetos (POO). Este paradigma nos ha permitido de parar a pensar en las funciones y empezar a pensar en los objetos. Con el encapsulamiento cada objeto debe tener sólo los métodos estrictamente relacionados con
este objeto y nada más. Y nuestras clases principales hacen "confianza" a las clases secundarias llamandolas sólo para que estas clases ejecuten sus propios métodos. Y estas clases ya "saben" cual de sus métodos hay que llamar para conseguir el resultado necesario! Lo que no se tiene que hacer en la POO, es empezar a sacar las propriedades de las clases para pasarlas a otras clases y crear un jaleo del código que nadie va poder seguir.
Así que en ese sentido Hibernate nos ofrece la
manera antigua y ineficaz a trabajar: con los datos y con un
procedimiento que manipula estos datos. La clase "Usuario" no se
utiliza como un objeto, de lo contrario como un almacenamiento temporal de
datos. Esto contradice los principios de la POO, que nos obliga a tener objetos encapsulados.
Un buen objeto según la POO no debería tener ni "getter" o
"setter" (que son la primera señal de que este no es un objeto OOP,
si no sólo un almacenamiento). Un buen objeto encapsula su lógica y su
comportamiento y no expone su lógica fuera.
DAO esta contra la POO
Por desgracia, en el mundo Java existen muchos ejemplos de la mala utilización de la POO: todos estos framework como Spring, Hibernate, Jackson, Hadoop - tratan de utilizar el paradigma procedimental en el mundo POO. Tratan de convertir el lenguaje Java en el
lenguaje C, con todos sus trozos enormes del código, donde no llegas ni a saber quien envía los datos y quien los gestiona. Donde cualquier objeto pueden acceder a cualquier objeto y cambiarlo. Donde se violan los principios básicos de la POO que aprendemos en la Uni. El propósito de Java - utilizar las ventajas de la
programación orientada a objetos. Este concepto hace el código más fácil a leer, fácil a mantener y fácil a probar.
La solución
La solución es muy sencilla:
Aquí nuestra clase principal delega al objeto Usuario toda la lógica
y funcionalidad para cambiar su nombre. Diciendole: "yo me confio en ti, haz tu trabajo y cuando acabes, traeme el resultado". En lugar de hacer "setName()" para tener que recuperarlo con "getName()" para luego pasarlo a otra parte, se utiliza "rename()" y punto. Se delega al objeto Usuario toda la responsabilidad a cambiar su nombre, conectar a la base de datos, actualizarla , etc.
Hay varias bibliotecas que podemos utilizar para conseguir este comportamiento. El concepto se llama ActiveRecord y en Internet podemos encontrar varias bibliotecas relacionadas a eso.
Abajo ponemos un ejemplo que utiliza JOOQ, una pequeña biblioteca para generar los SQL, pero hay varias.
Todas las operaciones de actualización de usuarios están encapsulados en el objeto de usuario y no son visibles fuera del objeto:
public class User {
private int id;
public User() {}
public int getId() {
return id;
}
public String retrieveName() {
return this.x.select("name")
.from("users")
.where("id", this.id)
.fetchOne();
}
public void updateName( String name ) {
this.x.update("user")
.set("name", name=
.where("id", this.id)
.execute();
}
}
Si uno quiere realizar transacciones, puede crear una clase adicional con un método que dice "transactional". De este modo, cada objeto (User y Order) puede ser llamado para que se auto-actualiza.
En el ejemplo anterior hemos utilizado JooQ, pero hay otro buen ejemplo implementado el concepto ActiveRecord llamado ActiveJPA, donde dejamos de trabajar con objetos DAO, sino directamente con los modelos.
En otras palabras, en este caso, ya no es necesario de obtener un objeto User para pasarlo a la sesión Hibernate, etc. No hacemos otra cosa que simplemente llamar el objeto User (que hereda de una clase llamada ActiveJPA org.activejpa.entity.Model) y este objeto actualiza a si mismo:
Hay varias bibliotecas que podemos utilizar para conseguir este comportamiento. El concepto se llama ActiveRecord y en Internet podemos encontrar varias bibliotecas relacionadas a eso.
Abajo ponemos un ejemplo que utiliza JOOQ, una pequeña biblioteca para generar los SQL, pero hay varias.
Todas las operaciones de actualización de usuarios están encapsulados en el objeto de usuario y no son visibles fuera del objeto:
public class User {
private int id;
public User() {}
public int getId() {
return id;
}
public String retrieveName() {
return this.x.select("name")
.from("users")
.where("id", this.id)
.fetchOne();
}
public void updateName( String name ) {
this.x.update("user")
.set("name", name=
.where("id", this.id)
.execute();
}
}
Si uno quiere realizar transacciones, puede crear una clase adicional con un método que dice "transactional". De este modo, cada objeto (User y Order) puede ser llamado para que se auto-actualiza.
En el ejemplo anterior hemos utilizado JooQ, pero hay otro buen ejemplo implementado el concepto ActiveRecord llamado ActiveJPA, donde dejamos de trabajar con objetos DAO, sino directamente con los modelos.
En otras palabras, en este caso, ya no es necesario de obtener un objeto User para pasarlo a la sesión Hibernate, etc. No hacemos otra cosa que simplemente llamar el objeto User (que hereda de una clase llamada ActiveJPA org.activejpa.entity.Model) y este objeto actualiza a si mismo:
User user = User.findById(id);
Map attributes = new HashMap();
attributes.put("name", name);
user.updateAttributes(attributes);
En este caso nos damos cuenta, que el principio de encapsulamiento se conserva y el código se ha hecho mucho más lógico y fácil a entender.
No hay comentarios:
Publicar un comentario