¿Como armar una Jerarquía de OO?

90 views
Skip to first unread message

gonzal...@gmail.com

unread,
Dec 20, 2012, 2:20:12 PM12/20/12
to node...@googlegroups.com
Hola, soy nuevo con esto de nodejs,y lo estoy usando a través de Express.

Estaba queriendo armar algo (usando Express) donde la bd MySQL la manejo manualmente (sin ORM), y por lo tanto me veo en la necesidad de armar una jerarquía de OO, básicamente para ahorrar código relativo a ella.

No tuve problemas en crear algunas Entidades "aisladas" (Persona,Localidad...) pero al momento de crear una Jerarquía se me complica en cuanto a implementación, más que no conozco mucho de JS en lo que es referido a esta naturaleza de problemas.

Para la Jerarquía cree al padre EntidadAbstracta, que tiene un aspecto así:
db=require('./db.js')

function EntidadAbstracta(obj){
  this.id=obj.id;
  ...
}

//Constantes relativas a cada entidad
EntidadAbstracta.TABLA=null
...

EntidadAbstracta.buscarPorId(id,callback){
   conexion=db.conectar()
   ...
}

exports.EntidadAbstracta=EntidadAbstracta

Ahora no se bien si un Esquema de Entidad padre así está bien. O sea en cuanto al uso del "exports" para hacer publico la Entidad, o bien deberia usarlo para los "métodos de Clase" (buscarPorId,filtrarPorCampo,etc...). SI es eficiente para "crear luego hijos",etc..

Y luego bien no se como definir los hijos, pensaba usar algo así:
EntidadAbstracta=require('./EntidadAbstracta.js').EntidadAbstracta

function Persona(obj){
  EntidadAbstracta.call(this,obj)
    ...
}
Persona.prototype=Object.create(EntidadAbstracta.prototype)

Me interesaria conocer como arman uds las jerarquias, y si de la forma que lo hago voy bien, o solo trae dolores de cabeza jeje.

Por el momento no logré probarlo al 100%, porque al definir un único hijo no logro ejectuar su método (heredado) buscarPorId(id,callback): me dice que no lo posee.

José F. Romaniello

unread,
Dec 20, 2012, 2:38:32 PM12/20/12
to node...@googlegroups.com
yo prefiero:

module.exports = EntidadAbstracta

EntidadAbstracta = require('/EntidadAbstracta.js')

y poner solo una clase por modulo, salvo para el index del  package o de un directorio... si es que tiene sentido hacerlo.

Por lo general no hago muchas clases y herencia de este tipo en javascript, casi siempre mis módulos exportan una función.

saludos






--
 
 

Carlos Villuendas Zambrana

unread,
Dec 20, 2012, 3:02:11 PM12/20/12
to node...@googlegroups.com
Hola,


Si quieres te pongo un caso práctico de como lo haría yo, y si tienes alguna duda me lo puedes ir comentando:

#EntidadAbstracta.js

var oDb = require( './db' );

var EntidadAbstracta = function( oObj )
{
this.nId = oObj.nId;
...
...
};

EntidadAbstracta.TABLA = null;

EntidadAbstracta.prototype.buscarPorId = function( id, callback )
{
   oConexion = oDb.conectar();
   ...
   ...

   process.nextTick( function(){
     callback( /**/ );
   } );

   /**
     Tal vez, podrías estudiar no solo usar callbacks en tu API y empezar a usar también promesas, créeme, puede llegar a ser mucho más fácil luego para tí
     trabajar con llamadas en bloque.
    */
};

module.exports = EntidadAbstracta;

# Persona.js

var EntidadAbstracta = require( './entidadabstracta' ),
    util = require( 'util' );

var Persona = function( oObj )
{
    EntidadAbstracta.apply( this, arguments );
};

util.inherits( Persona, EntidadAbstracta );

Persona.prototype.buscarPorId = function( id, callback )
{
   // Sobreescribes el comportamiento del método en la clase padre.
};

module.exports = Persona;


#######

Básicamente así creas una clase padre y las clases hijas. Y estaría bien que tuvieras un fichero por clase. Luego échale un ojo a la función inherits del módulo util, es bastante útil :P.

Espero que este más o menos claro.

Por último, veo que llamas a tu clase como Abstracta, pero metes implementación en lo métodos. Tal vez deberías cambiarle el nombre a la clase. O asegurarte que todos los métodos de tu clase son sobreescritos por clases hijas. Para ello lo mejor que puedes hacer es algo como esto:

EntidadAbstracta.prototype.buscarPorId = function( id, callback )
{
  throw new Error( 'Este método debe ser sobreescrito' );
};

Espero que te ayude con lo que estés montando. Cualquier cosa das el toque. 

Un Saludo,

CARLOS.






--
 
 

gonzal...@gmail.com

unread,
Dec 21, 2012, 12:14:38 PM12/21/12
to node...@googlegroups.com
Muchísimas gracias a ambos por sus prontas respuestas!.

Voy a probar armar la jerarquía de la forma que me describiste Carlos, y mas que nada usando el método inherits jeje. Y tenias razón, el nombre presta confusión (mas al consultarles a uds), en realidad deberia renombrarlo a algo como "EntidadBase".

Poniendo el ejemplo de como lo armarías, me sirve para verlo bien claro ;). Cualquier cosa sino consulto jeje.

Saludos!

gonzal...@gmail.com

unread,
Dec 22, 2012, 12:23:33 AM12/22/12
to node...@googlegroups.com
Creo que mejor aclaro un poco cual era mi idea, porque me di cuenta que no exprese todo, y el tema de la herencia en JS me vuelve medio loco jeje. Mas que tengo una base de Java, y la flexibilidad de JS me marea jaja.

Mi idea de la jerarquia era tener un padre que auspice de DAO (x el tema de la BD). Yo quería a ese padre (EntidadAbstracta, ahora llamado EntidadBase) que tuviera "métodos de clase" (statics, no requieren instanciación): buscarPorId, filtrar...insertar. Por otro lado algunas constantes y/o funciones que serian las que tendrían relevancia en los hijos: nombre de la Tabla, id de la Entidad.

Ahora dado que mi base de JS es media pobre, al intentar emular la herencia se me complico, mas esta idea que tenia en mente.

Por otro lado, tengo entendido que EntidadBase.buscarPorId=func.. seria un "método de clase",y EntidadBase.prototype.buscarPorId=funct.. uno propio del objeto. Lo que note es que al hacer herencia, ya sea via utili.inherits o Object.create(EntidadBase.prototype) no heredo los de clase. Esto hizo que en el hijo (Entidad) sobreescribiera el método llamando al del padre via call, asi logre ejecutarlo con los datos del hijo (tabla, id, incluso lograr instanciar su clase). Es mas yo deseaba que el padre "instancie a los hijos" cuando use el buscarPorId..etc.

Asi que tengo implementado algo a lo "bruto" EntidadBase y Entidad. ¿Como logro heredar esos metodos de clase?. Parte de la mala implementacion es por mi base de JS + el problema ese de los metodos no heredados, y por eso puse algunas lineas bastantes sucias.

En el codigo se ve ni necesdidad de instanciar en el padre a los hijos: use primero una "constante" (algo bien chancho) Entidad.constanteClase, pero después, dado mi problema, en el hijo hago un:

Entidad.buscarPorId=function(id,callback){
  EntidadBase.buscarPorId.call(this,id,callback)
}

Y con esto, en el padre aprovecho a crear un hijo.

El tema de explayarme es para aprovechar mejor la consulta, ver si el esquema sirve o no,etc. Y segundo se que con nodejs, no podría convertir los métodos de clase a "públicos del modulo" (exports.EntidadBase.buscarPorId...), porque no me servirían para la jerarquía. Tal vez tenga mal entendido los conceptos.

Si consideran que ahora mi consulta excede los temas  a tratar en el grupo, les pido disculpas de antemano. Desde ya les agradezco!!!

Angel Java Lopez

unread,
Dec 22, 2012, 3:38:42 AM12/22/12
to node...@googlegroups.com
Hola gente!

Gonzalo, no se si segui vi tus emails y tengo todo tu contexto... pero asi, a simple vista, yo tendria objetos repositorios, uno por cada tipo de entidad, y ahi pondria buscarPorId. Ya no tendrias el tema de "heredar metodos de clase" ni nada por el estilo.

Asi, a mano alzada, escribiria:

function Repositorio(lista) { // recibe lista de entidades
    this.lista.buscarPorId = function(id) {
          var n = lista.length;
          for (var k=0; k<n; k++)
                if (lista[k].id == id)
                     return lista[k];
          return null;
    }
}

luego, mas adelante, escribira ese repositorio para una entidad, contra una base relacional (o por que no, una NoSQL como mongodb).

Luego, al tener DOS repositorios de entidades contra una base de datos, recien ahi comenzaria a abstraer.

Y asi como Caton el Viejo terminaba todos sus discursos (sin importar de que tema eran) con la frase "Carthago delenda est" yo termino:

NO HARIA NADA DE ESTO SIN TDD ;-) ;-)

Angel "CatoTheElder" Lopez

2012/12/22 <gonzal...@gmail.com>

--
 
 

Carlos Villuendas Zambrana

unread,
Dec 22, 2012, 6:47:00 AM12/22/12
to node...@googlegroups.com
Hola,

Creo que ahora entiendo mejor lo que quieres hacer. Aunque si te digo la verdad, no me queda muy claro por que no quieres que la Base sea una clase y los hijos hereden de ella. Por que al final los hijos si deben ser clases que tu vas a instanciar. Si no lo haces así tu estructura ya no seguirá el principio de sustitución de Liskov ( http://en.wikipedia.org/wiki/Liskov_substitution_principle ). Pero bueno, teorías a parte, lo que yo haría para lograr algo como lo que tienes en mente sería algo así:


#entidadbase.js

var EntidadBase = {
  buscarPorId: function( entity ){
    return function( id, cb ){
      /* Implementación donde ya puedes usar entity para lo que necesites*/ 
    db.connection( entity.TABLA, cb );
    }
  },

 buscarPorConsulta: function( entity ){
    return function( id, cb ){
      /* Implementación */
    }
  }
}

module.exports.inherit = function( entidad )
{

  for( metodo in EntidadBase )
  {
    if( EntidadBase.hasOwnproperty( metodo ) )
    {
      entidad.prototype[metodo] = EntidadBase[metodo](entidad);
    }
  }

};

# persona.js

var base = require( './entidadbase' );

var Persona = function(){
};

Persona.TABLA = 'persona';
Persona.OTRACONSTANTEDECLASE = 123;

base.inherit( Persona );

Persona.prototype.otroMetodoDeInstancia = function(){};




Bueno, ya se que se ve un poco ortopédico, y la verdad que lo es. Básicamente así logras tener todos los método estáticos de tu módulo base, como métodos de clase, ya correctamente configurados para que puedan usar los datos de la tabla correcta y tal.

Pero ya te digo que no es algo que yo haría. Básicamente porque no es muy SOLID algo así.

Espero que esto te ayude, cualquier cosa nos comentas.

Un Saludo,
CARLOS.


--
 
 

gonzal...@gmail.com

unread,
Dec 24, 2012, 5:22:40 PM12/24/12
to node...@googlegroups.com
Gracias por sus respuestas!. Las tengo muy encuenta!!. Es mas ya estoy pensando en despues cuando este mas canchero con nodejs instalar nodejs-units o usar su modulo assert, como comentaba Angel con respecto del TDD :D.

Por el momento logre hacer lo que queria haciendo el metodo "hereda" (como indicaba Carlos) en EntidadBase y en el hijo simplemente hago esto: exports.Entidad= EntidadBase.hereda(Entidad), y con esto logro "enchufarle" los métodos que yo les llamo "de clase" (como en Java) ;).

Aun asi sus comentarios, me hiceron darme cuenta que es bastante "chancho" lo que estoy haciendo, aunque es muy cómodo jeje :), pero voy a tener problemas cuando haga otros métodos en el "Padre-DAO" y/o en sus hijos. Asi que a la larga mejorare esto ;).

Saludos, y mil gracias por sus respuestas!, son de gran ayuda para mí.

pd: Feliz Navidad! ;)
Reply all
Reply to author
Forward
0 new messages