Ir al contenido


Foto

estructura de un proyecto orientado a objetos


  • Por favor identifícate para responder
16 respuestas en este tema

#1 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 03 abril 2016 - 10:41

Hola nuevamente por aqui...

 

queria dejar la prog estructurada aunque sea para probar... y uitilizar poo..

 

El caso es que decidi colocar las clases en archivos.pas separados e incluirlos despues..en cada modulo del proyecto incluir el .pas de la clase que necesite.

 

Esto lo aprendi de un lenguaje de scripting: php. donde es bueno tener cada clase con su contructor y destructor en un archivo distinto.. es correcto asi?

 

 


  • 2

#2 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 03 abril 2016 - 10:54

Hola, no necesariamente,  en algunos lenguajes crean una clase por cada archivo, pero en realidad se pueden crear muchas clases en un solo archivo, siempre y cuando en su conjunto correspondan a la misma cosa.  Ej.  Yo tengo una clase llamada Base de datos, que contiene clases tablas, vistas, campo, llaves, etc.   así que en un solo archivo cree todas las clases, y diseñadas de tal manera que si algún dia se requiere se puedan extender de las clases padres,  ej.  la clase tabla tiene unas características genéricas para todas las tablas, pero ya para una clase tabla de postgres, se hereda y se especializa, según la necesidad, pero esa nueva clase si la utilizó en otro archivo,  así me parece más ordenado,  que tener estrictamente un archivo por clase, terminando con 100 archivos.

 

Saludos.


  • 0

#3 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 03 abril 2016 - 12:55

Hola, no necesariamente,  en algunos lenguajes crean una clase por cada archivo, pero en realidad se pueden crear muchas clases en un solo archivo, siempre y cuando en su conjunto correspondan a la misma cosa.  Ej.  Yo tengo una clase llamada Base de datos, que contiene clases tablas, vistas, campo, llaves, etc.   así que en un solo archivo cree todas las clases, y diseñadas de tal manera que si algún dia se requiere se puedan extender de las clases padres,  ej.  la clase tabla tiene unas características genéricas para todas las tablas, pero ya para una clase tabla de postgres, se hereda y se especializa, según la necesidad, pero esa nueva clase si la utilizó en otro archivo,  así me parece más ordenado,  que tener estrictamente un archivo por clase, terminando con 100 archivos.

 

Saludos.

Muchas gracias..

 

Estoy intentando por ejemplo el singleton en el servidor datasnap para conectar a la bd.. aunque la conexion se hace en el oncreate una sola vez...

Y lo mismo en el cliente: quiero usar el singleton para evitar multiples llamadas a


php
  1. a:=TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection);

no se si estaria bien.. pero no quiero crearlo cada vez que necesito llamar a un metodo.


  • 0

#4 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 03 abril 2016 - 01:56

El tema de tener muchas unidades para mi no es un problema, mas bien al contrario. Es cierto que lleva mas tiempo y el cambio es bastante radical y se desorganiza un poco la cabeza, pero a la larga te termina jugando a favor
 
En terminos Object-Pascaleros, acoplamiento significa que tenes que poner en el uses una unidad de codigo
 
Por ende, reducir el acoplamiento es tratar de agregar siempre lo minimo posible en el uses; esto es mas que nada para la seccion de interface. La seccion interface es la parte publica de una unidad, es lo que exporta; todo lo que este en esta seccion lo pueden ver quienes usen esta unidad
 
En la seccion de implementation, como se trata de la parte privada de la unidad, no deberia importar que unidades usemos, ya que eso forma parte de los detalles de implementacion, y la interface promete cierta funcionalidad abstrayendo la complejidad
 
Podria hacerse una analogia con las clases y las secciones private y public. Al que usa la clase solo le interesa usar la funcionalidad disponible, sin importar en como estará implementada
 
Ahora, muchos podrian decir que se trata de "balance" entre lo publico y lo privado, pero yo no lo veo asi: Hay una sola realidad y es que una clase bien diseñada debe (vuelvo a repetir) proveer funcionalidad escondiendo el como esta implementada
 
Un ejemplo trivial:
 


delphi
  1. type
  2. TFactura = class
  3. private
  4. FListDetalles: TList<TDetalle>;
  5. public
  6. property ListaDetalles: TList<TDetalle> read FListDetalles;

A simple vista se puede ver un fragmento de una clase que parece bastante idiomatico en Delphi: en cualquier tutorial se puede encontrar ejemplos similares a este. Hay una variable de instancia privada que mantiene una lista de Detalles y una propiedad publica que permite acceder a la misma lista, de manera "segura"
 
Perdon, dije de manera segura?
 
Es eso esconder los detalles de implementacion? No lo creo. Cualquiera que use esa clase TFactura tiene acceso a un objeto TList, y puede hacer con el lo que se le de la gana
 
Puede invocar al metodo Free; puede invocar al metodo Clear; puede invocar a metodos Add, Delete, Insert, etc
 
Es eso lo que queremos para el que use la clase? 
 
Podriamos eliminar la propiedad; pero ahora la clase es inutil. Esto es una realidad: no se puede crear un sistema si no se usa un minimo nivel de acoplamiento; si los objetos no se conocen entre si y no colaboran, basicamente no tenes nada.
 
El secreto esta en acoplarse a clases lo mas sencillas posibles. Por ejemplo, una implementacion mas elegante seria devolver una coleccion de solo lectura y no la lista per se. De esta manera, el que usa la clase obtiene acceso a las lineas de la Factura para poder listarlas en pantalla o lo que sea necesario
 
Necesitan agregar mas lineas a la factura? No hay problema, se deberia proveer un metodo Add que, a fin de cuentas va a terminar insertando en la lista, pero de manera segura, por ejemplo la clase Factura querria validar que lo que quieren insertar no sea nil, que no tenga precio 0, que el producto sea valido, que haya stock, etc etc
 
Y lo bueno de esto es que si por ejemplo se quiere cambiar la implementacion interna (TList) por otra implementacion, las clases que antes usaban TFactura no deberian enterarse de nada
 
Vuelvo al tema de tener muchas unidades de codigo; el tener muchas unidades de codigo significa que estas separando lo maximo posible las clases entre si. Esto disminuye un poco el nivel de acoplamiento (porque aun asi, las clases que estan en una misma unidad se "conocen" entre si). La idea es crear unidades de codigo compactas, simples y pequeñas, de forma tal que puedas reutilizarlas en otro proyecto sin tener que arrastrar dependencias, es decir, agarro y pongo la misma clase  TFactura en el otro proyecto de al lado
 
Si en una misma unidad tenes muchas clases, hay mas posibilidades de que esas clases utilicen otras unidades de codigo del dominio del proyecto del que vienen
 
 
A mi en particular me gusta crear muchas unidades, en muchas por ejemplo tengo definidas solamente tipos enumerativos, con su correspondiente record helper; en otros casos tengo solamente definida una o dos interfaces con pocos metodos, y luego las implemento en otra unidad
 
Un ejemplo facil de entender es el que publique hace poco 
 
Y si bien es cierto que es algo bastante simple me he dado cuenta de que esta bien diseñado cuando hice la "traduccion" a FreePascal y no he tenido que tocar nada de mi codigo (excepto algunos pormenores relacionados al soporte para genericos de FreePascal que es un poco distinto al de Delphi, por ejemplo no se permiten genericos "anidados" es decir TList<TClase<Integer>> eso no se puede)
 
Tambien me he dado cuenta (y por eso lo hice asi en el demo) que puedo cambiar la implementacion, lo que ocurre tras los bastidores incluso en tiempo de ejecucion:

0b59d8b63271eb9c7a63944f7637ef56o.jpg
 
Osea yo puedo decir que quiero usar Synapse y el parser lkJSON, o NetHTTP y System.Json, o cualquier combinacion, y todo funciona bien (y sigo usando la misma clase)
 
Eso es tener clases bien separadas, cada una en su correspondiente unidad de codigo (en FreePascal no tenemos System.Json, si hubiese puesto todos los parser de Json en un solo archivo "porque son de la misma familia", tendria que haber modificado el archivo para sacar las referencias a System.Json, o bien poner IFDEF en media unidad) y acoplamiento al minimo (porque las clases del sistema no se conocen realmente por nombre y apellido, conocen solamente una parte, la interface)
 
Saludos y happy coding :)


Editado por Agustin Ortu, 03 abril 2016 - 01:57 .

  • 1

#5 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 05 abril 2016 - 04:47

Claro...muchas gracias..

 

y se deben tener clases tanto en un servidor datasnap como en el cliente? es decir se aplica a cualquier aplicacion...


  • 0

#6 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 05 abril 2016 - 07:40

Si quieres propones un proyecto (pequeño) y lo vamos evaluando aquí, haciendo diferentes propuestas,  porque la POO también tiene muchas formas de implementarla y depende del estilo de cada programador.

 

En mis clases, siempre propongo un editor de gráficos,  con objetos como líneas, círculos, rectángulos, etc.   No se si ese te parece para entender el concepto.  y entre todos vamos aportando.

 

Saludos.


  • 0

#7 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 05 abril 2016 - 07:49

Si quieres propones un proyecto (pequeño) y lo vamos evaluando aquí, haciendo diferentes propuestas,  porque la POO también tiene muchas formas de implementarla y depende del estilo de cada programador.

 

En mis clases, siempre propongo un editor de gráficos,  con objetos como líneas, círculos, rectángulos, etc.   No se si ese te parece para entender el concepto.  y entre todos vamos aportando.

 

Saludos.

No estaria mal...estoy por recibirme de analista de sistemas.. pero es que nunca hice un proyecto real.. y bueno simplemente por saber la estrcutura en delphi...

Saludos


  • 0

#8 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 12 abril 2016 - 06:02

Y otra cosa.. tambien pueden haber interfaces o clases abstractas en unidades apartes que luego sean implementadas o realizadas por las clases concretas..

Enviado desde mi SM-G530M mediante Tapatalk
  • 0

#9 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 12 abril 2016 - 06:53

En realidad es lo ideal. Al momento de hacer los test de unidad es mucho más sencillo tener unidades con interfaces y no incluir la implementación. La implementación puede arrastrar dependencias y eso te obliga a meter esas dependencias en el proyecto de test
  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.301 mensajes
  • LocationArgentina

Escrito 12 abril 2016 - 07:10

Hola, no necesariamente,  en algunos lenguajes crean una clase por cada archivo, pero en realidad se pueden crear muchas clases en un solo archivo, siempre y cuando en su conjunto correspondan a la misma cosa.  Ej.  Yo tengo una clase llamada Base de datos, que contiene clases tablas, vistas, campo, llaves, etc.   así que en un solo archivo cree todas las clases, y diseñadas de tal manera que si algún dia se requiere se puedan extender de las clases padres,  ej.  la clase tabla tiene unas características genéricas para todas las tablas, pero ya para una clase tabla de postgres, se hereda y se especializa, según la necesidad, pero esa nueva clase si la utilizó en otro archivo,  así me parece más ordenado,  que tener estrictamente un archivo por clase, terminando con 100 archivos.

 

Saludos.

 

Cohesión = "Cuando en conjunto correspondan a la misma cosa" ;)

 

El tema de tener muchas unidades para mi no es un problema, mas bien al contrario. Es cierto que lleva mas tiempo y el cambio es bastante radical y se desorganiza un poco la cabeza, pero a la larga te termina jugando a favor
 
En terminos Object-Pascaleros, acoplamiento significa que tenes que poner en el uses una unidad de codigo
 
Por ende, reducir el acoplamiento es tratar de agregar siempre lo minimo posible en el uses; esto es mas que nada para la seccion de interface. La seccion interface es la parte publica de una unidad, es lo que exporta; todo lo que este en esta seccion lo pueden ver quienes usen esta unidad
 
En la seccion de implementation, como se trata de la parte privada de la unidad, no deberia importar que unidades usemos, ya que eso forma parte de los detalles de implementacion, y la interface promete cierta funcionalidad abstrayendo la complejidad
 
Podria hacerse una analogia con las clases y las secciones private y public. Al que usa la clase solo le interesa usar la funcionalidad disponible, sin importar en como estará implementada
 
Ahora, muchos podrian decir que se trata de "balance" entre lo publico y lo privado, pero yo no lo veo asi: Hay una sola realidad y es que una clase bien diseñada debe (vuelvo a repetir) proveer funcionalidad escondiendo el como esta implementada
 
Un ejemplo trivial:
 


delphi
  1. type
  2. TFactura = class
  3. private
  4. FListDetalles: TList<TDetalle>;
  5. public
  6. property ListaDetalles: TList<TDetalle> read FListDetalles;

A simple vista se puede ver un fragmento de una clase que parece bastante idiomatico en Delphi: en cualquier tutorial se puede encontrar ejemplos similares a este. Hay una variable de instancia privada que mantiene una lista de Detalles y una propiedad publica que permite acceder a la misma lista, de manera "segura"
 
Perdon, dije de manera segura?
 
Es eso esconder los detalles de implementacion? No lo creo. Cualquiera que use esa clase TFactura tiene acceso a un objeto TList, y puede hacer con el lo que se le de la gana
 
Puede invocar al metodo Free; puede invocar al metodo Clear; puede invocar a metodos Add, Delete, Insert, etc
 
Es eso lo que queremos para el que use la clase? 
 
Podriamos eliminar la propiedad; pero ahora la clase es inutil. Esto es una realidad: no se puede crear un sistema si no se usa un minimo nivel de acoplamiento; si los objetos no se conocen entre si y no colaboran, basicamente no tenes nada.
 
El secreto esta en acoplarse a clases lo mas sencillas posibles. Por ejemplo, una implementacion mas elegante seria devolver una coleccion de solo lectura y no la lista per se. De esta manera, el que usa la clase obtiene acceso a las lineas de la Factura para poder listarlas en pantalla o lo que sea necesario
 
Necesitan agregar mas lineas a la factura? No hay problema, se deberia proveer un metodo Add que, a fin de cuentas va a terminar insertando en la lista, pero de manera segura, por ejemplo la clase Factura querria validar que lo que quieren insertar no sea nil, que no tenga precio 0, que el producto sea valido, que haya stock, etc etc
 
Y lo bueno de esto es que si por ejemplo se quiere cambiar la implementacion interna (TList) por otra implementacion, las clases que antes usaban TFactura no deberian enterarse de nada
 
Vuelvo al tema de tener muchas unidades de codigo; el tener muchas unidades de codigo significa que estas separando lo maximo posible las clases entre si. Esto disminuye un poco el nivel de acoplamiento (porque aun asi, las clases que estan en una misma unidad se "conocen" entre si). La idea es crear unidades de codigo compactas, simples y pequeñas, de forma tal que puedas reutilizarlas en otro proyecto sin tener que arrastrar dependencias, es decir, agarro y pongo la misma clase  TFactura en el otro proyecto de al lado
 
Si en una misma unidad tenes muchas clases, hay mas posibilidades de que esas clases utilicen otras unidades de codigo del dominio del proyecto del que vienen
 
 
A mi en particular me gusta crear muchas unidades, en muchas por ejemplo tengo definidas solamente tipos enumerativos, con su correspondiente record helper; en otros casos tengo solamente definida una o dos interfaces con pocos metodos, y luego las implemento en otra unidad
 
Un ejemplo facil de entender es el que publique hace poco 
 
Y si bien es cierto que es algo bastante simple me he dado cuenta de que esta bien diseñado cuando hice la "traduccion" a FreePascal y no he tenido que tocar nada de mi codigo (excepto algunos pormenores relacionados al soporte para genericos de FreePascal que es un poco distinto al de Delphi, por ejemplo no se permiten genericos "anidados" es decir TList<TClase<Integer>> eso no se puede)
 
Tambien me he dado cuenta (y por eso lo hice asi en el demo) que puedo cambiar la implementacion, lo que ocurre tras los bastidores incluso en tiempo de ejecucion:

0b59d8b63271eb9c7a63944f7637ef56o.jpg
 
Osea yo puedo decir que quiero usar Synapse y el parser lkJSON, o NetHTTP y System.Json, o cualquier combinacion, y todo funciona bien (y sigo usando la misma clase)
 
Eso es tener clases bien separadas, cada una en su correspondiente unidad de codigo (en FreePascal no tenemos System.Json, si hubiese puesto todos los parser de Json en un solo archivo "porque son de la misma familia", tendria que haber modificado el archivo para sacar las referencias a System.Json, o bien poner IFDEF en media unidad) y acoplamiento al minimo (porque las clases del sistema no se conocen realmente por nombre y apellido, conocen solamente una parte, la interface)
 
Saludos y happy coding :)

 

Agustín, comparto lo que dices que una clase debe estar bien equilibrada y ofrecer una interfaz pública que evite algunos vicios... como de estar "propagando" un List en tu ejemplo. Lo más adecuado, si uno quiere mantener el purismo OO, es que la clase ofrezca justamente métodos AddFactura, etc. y oculte el uso del List. Yo suelo hacer justamente esto en mis clases "Lista de..."

En lo que no estoy muy de acuerdo es en tener muchas unidades, sobre todo si se llega al planteo de unidades monolíticas (con una sola clase como es práctica común encontrarse en JAVA). No necesariamente tener más es sano. Uno puede estar tentado a pensar que con eso se reduce el acoplamiento. En parte tiene razón, tener una cantidad baja en uses ofrece un acomplamiento a la baja. Ahora bien, no por mucho bajar se está haciendo bien las cosas. Un diseño patológico conducirá a una clase que no aprende a acoplarse y a un problema de pérdida de delegación y concentrar muchas actividades que bien podría delegar en otras.

 

El problema está en realidad en una ambiguación del concepto. Podríamos decir que el acoplamiento se debe distinguir a 2 escalas: el acoplamiento interno y el acoplamiento externo. El interno hace al propio acoplamiento entre las clases y tipos dentro de una unidad. Mientras que el externo es el acoplamiento que se presenta entre unidades.

 

Cuando tenemos dos o más clases amigas es normal ver que trabajan de manera cooperativa. Están fuertemente acopladas entre si, pero a su vez mantienen una Cohesión a nivel Funcional (La más alta de las cohesiones). Es normal en estos casos ver que están en una misma unidad. Desde el punto de vista externo el acoplamiento es bajo. Un buen ejemplo de esto lo puedes encontrar el TColletion y TColletionItem, aplicando el concepto de composición agregada o simplemente también conocida como Agregación.

 

La relación entre Acoplamiento y Cohesión no siempre es inversa. Hay una buena cantidad de casos en los que cuando aumenta una, la otra baja. Pero depende de la naturaleza del problema en realidad.

Lo que yo he notado es que es muchos se preocupan mucho por el Acoplamiento, pero el concepto Cohesión les resulta ajeno. Es medio difícil verlo puesto que por lo general la Cohesión es un aspecto más interno a la clase que externo.

 

En lo que también difiero es el Principio Abierto-Cerrado. Necesariamente hay que ser equilibrado. En el mundo del Software existe el gris. Si, es cierto que una clase debe ofrecer una interfaz pública lo más amigable posible y ocultar detalles externos que no vienen al caso. Pero tal principio también señala que a su vez debe ofrecer una interfaz lo suficientemente abierta para poder extenderse y dar a conocer algunos aspectos que también podrían ser de interés. Es así como surge el concepto de protegido.

 

No puedes reducir el principio a que existe una única realidad. Tal pensamiento te llevará a un pensamiento binario. Una clase bien diseñada ofrecerá equilibrio entre público, privado, protegido. La aparición del concepto Helper, tan de moda en ti por lo que he estado viendo, es justamente una violación a ese equilibrio. Aunque más que violación lo correcto sería una falta de comprensión de lo que implica y abarca el principio.

 

Es normal que los diseños OO vivan. Algo que ha nacido privado resulta ser que ahora es necesario darle visión pública. Lo vemos en como fue evolucionando la VCL desde D4 a D6. Sufrió unos cuantos cambios, y para la llegada de D2006 la VCL siguió evolucionando a una escala mayor. La añadición de los Helper fue una solución del tipo "Hack" como le dicen. Para no verse complicados por el alcance de los cambios, vinieron los Helpers como llaves maestras que permitían entrar en las clases y dar ese aspecto gris que tu niegas.

Justamente el reduccionismo y la mala comprensión del principio lleva a esa dualidad, cuando en realidad es más que eso.

Un purista OO te diría que los Helpers no debieran de existir, si las cosas se hicieran con previsibilidad.

 

Saludos,


  • 1

#11 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 12 abril 2016 - 08:35

Amigo Marchelo, hablaste bien
 
Yo entiendo lo que decis y compartimos algunas cosas y otras no tanto :)
 
Es cierto que Cohesion es un concepto muy dificil de entender,y que puede parecer chocante cuando se lo quiere integrar con todas las otras ideas que andan dando vueltas. Aun no domino como me gustaria este aspecto
 
El principio de abierto-cerrado es muy interesante. Hay muchas formas de satisfacerlo. Por ejemplo implementando un patron Template, en donde hay una clase abstracta que define en su seccion protegida varios metodos que necesitan implementacion, o que necesitan algun refinamiento, implementado por las subclases concretas; mientras que la abstracta se dedica a invocar metodos que "aun no tienen codigo"
 
El modelo que estoy siguiendo ultimamente es medio de "yo se hacer esto, pero necesito aquello otro, dame alguien que sepa hacerlo". Lo implemento a partir de interfaces porque tienen la ventaja que los framework de unit testing te crean los mock y stub en un abrir y cerrar de ojos
 
De esta forma cumplo con el principio abierto-cerrado, me hago amigo de algo mas simple que una clase (una interface) y el acoplamiento es bajo
 
Ademas de que es mas facil delegar implementacion, en Delphi tenemos una palabra clave que es espectacular: implements
 
Yo puedo declarar una clase que implementa una serie de interfaces, y si no coloco todos los metodos de dichas interfaces, voy a obtener un error de compilacion. Ahora, esta palabrita implments lo que te permite es declarar la clase como que implementa la interface, pero implementarla en otra clase
 
Por ej:
 


delphi
  1. ISaltarin = interface
  2. procedure Saltar;
  3. end;
  4.  
  5. TAnimalSaltarin = class abstract(TInterfacedObject, ISaltarin)
  6. strict private
  7. FImplSaltarin: ISaltarin;
  8. public
  9. constuctor Create(const AImplSaltarin: ISaltarin);
  10. property FormaDeSaltar { a falta de un mejor nombre... } read FImplSaltarin implements ISaltarin;
  11. end;

No me he fijado si en FPC hay soporte para algo semejante. Pero es algo muy interesante que he oido decir a gente que programa en Java y en Delphi que "esto lo tiene Delphi y Java no y..."

 

De esta manera, podria implementar un descendiente y este codigo funciona:


delphi
  1. type
  2. TSaltamones = class(TAnimalSaltarin)
  3. { bla bla }
  4. end;
  5.  
  6. TSaltadorConUnaPata = class(TInterfacedObject, ISaltarin);
  7. public
  8. procedure Saltar;
  9. end;
  10.  
  11. procedure TSaltadorConUnaPata.Saltar;
  12. begin
  13. WriteLn('Salta y salta sobre una pata..');
  14. end:
  15.  
  16. var
  17. ASaltamontes: ISaltarin;
  18. begin
  19. ASaltamontes := TSaltamontes.Create(TSaltadorConUnaPata.Create));
  20. ASaltamontes.Saltar;
  21. end; 

 
 
Con respecto a los Helper, no suelo usar ayudantes de clases, a menos que sea muy necesario. Por ejemplo, no me gusta meterle la mano a clases que son ajenas o de terceros. Entonces directamente implemento el class helper. En otros casos simplemente lo uso para una cuestion de "syntaxis sugar".
 
A ver por ejemplo la clase TStrings no tiene un metodo Add que permita especificar formato; lo mismo para las rutinas MessageDlg. En cambio, si existe una version ShowMessageFmt!
 
Condenados los malditos que no escribieron los metodos AddFmt y MessageDlgFmt (o versiones sobrecargadas). En Lazarus si que existen
 
Entonces una forma de solucionarlo es usando herencia y agregar el metodo. Pero la herencia tiene el problema de que es verticalista, y TStrings es una clase estandar, abstracta y que se usa en todos lados. Osea, todo el mundo desciende de TStrings, no desciende de tu clase! Como se soluciona?
 
Podrias usar un Decorator, podria usar un Adapter, un Interceptor, que se yo!
 
Para este caso los ayudantes de clase vienen al rescate. 
 
Comparto lo que dices que usarlos como el viejo truco de la clase interpuesta es como agarrar la maza y el cortafierro,y arrancar a romper. En un principio esta feo, probablemente este mal. Ahora, que pueda haber un caso en que sea justificado.. es otra cosa (aca es donde entra el gris)
 
No uso tanto los class helper, pero los que si uso bastante son los record helper. El tema es que no los uso como ayudantes de registros, sino de tipos primitivos (ahora la cosa cambia)
 
Osea, uno puede decir IntToStr(5) o puede decir 5.ToString (a mi me gusta mas esta sintaxis) y ademas se pueden ir encadenando: 5.ToString.ToFloat, etc. El equivalente combinando las rutinas de SysUtils es mas dificil de leer
 
Es interesante usarlo para enumerativos
 


delphi
  1. TTipoMateria = (tmOrganica, tmInorganica);

( No me acuerdo un carajo de biologia, por ahi puse una estupides )
 
Ahora, el enumerativo es interesante porque es un ordinal, puedo usarlo para crear sets (otra caracteristica de Delphi que muchos de los chicos de C y Java envidian), etc
 
Pero es muy comun que en algun punto del programa necesitemos convertirlo a una representacion en string.
 
Entonces escribimos los metodos:
 


delphi
  1. function TipoMateriaToStr(const ATipoMateria: TTipoMateria): string
  2. begin
  3. case ATipoMateria of
  4. tmOrganica: Result := ' Orgánica ';
  5. tmInorganica: Result := ' Inorgánica ';
  6. else
  7. raise Exception.Create('Tipo de materia desconocido!!');
  8. end;
  9. end;

Lo cual sirve y funciona bien, simplemente es una sintaxis que no me gusta (a esto le llamo sintaxis sugar)
 
A mi me gustaria poder escribir esto:
 


delphi
  1. var
  2. Value: TTipoMateria;
  3. begin
  4. Value := tmOrganica;
  5. ShowMessage(Value.ToString); // esto me gusta
  6. ShowMessage(TipoMateriaToStr(Value)); // este no me gusta tanto :(
  7. end;

Fijate que en la implementacion, le deje un blanco a izquierda y derecha del string, medio a proposito
 
Para "solucionarlo" sin tocar ese metodo, puedo usar un Trim


delphi
  1. ShowMessage(Value.ToString.Trim);

Fijate como queda mucho mas legible que el equivalente con la sintaxis vieja (ok, en realidad esta un poco en el gusto de cada uno)


delphi
  1. ShowMessage(Trim(TipoMateriaToStr(Value));

Pero no! intento no usar los ayudantes para "manosear" implementacion

 

Saludos

 

La charla esta muy interesante


Editado por Agustin Ortu, 12 abril 2016 - 08:40 .

  • 0

#12 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.301 mensajes
  • LocationArgentina

Escrito 12 abril 2016 - 11:44

Desde el punto de vista de como es que los Helpers se meten y tocan el paradigma, resulta muy interesante.

Es un ejercicio que yo tengo pendiente en estudio, y que lo que conozco es por alguna leída en algún que otro lado. No he tocado hasta el momento el tema, y desconozco que tanto soporte tiene Lazarus sobre Helpers.

 

Yo he visto unos cuantos ejemplos tuyos en CD y me parece interesante el concepto para estudio y análisis. Pero me pregunto hasta que punto esa navaja suiza nos ayuda, y cuando nos cortamos por querer sacar el destornillador que está al lado de la tijera.

 

El uso en los enumativos confieso que me atrae. La verdad que hacer un Enum.ToString tiene su encanto y más de una vez me quedado pensando porqué no...

 

Yo también tengo en algunos trabajos interfaces. Las uso, y hasta se debatió el tema. Aunque no me gusta enamorarme demasiado... Lo que no me convence mucho es que nos veamos inclinados y casi obligados a tener que heredar de TInterfacedObject. Podemos evitarnos esa herencia, pero de hacerlo deberá ser nuestra responsabilidad implementar el sistema de conteo de referencia, que justamente es lo que ya hace TInterfacedObject.

Yo soy de la idea de tener mi propios árboles de herencia y de clases lo más limpia posible de clases externas. Y aún habiendo usado interfaces, sigo sintiendo algo de "ruido" ese TInterfacedObject metiéndose en algunas mis ramas.

Si el compilador se encargara de hacer el trabajo del conteo de referencia sin necesidad de haber metido esa clase y hacerlo de forma transparente de forma automática para mi sería estupendo. Algo como "Ha, está declarando que tal clase usa una interface. Entonces aquí debemos hacer conteo de referencias".

 

El principio abierto-cerrado, que quizá debiera llamarse Principio Abierto, Protegido, Cerrrado es extensible. Puede estirarse y contraerse según la naturaleza del análisis que llevemos. En la medida que vamos explorando las ramas del árbol de herencia de nuestras clases, vamos notando como varía el "porcentaje" o relación entre lo Público y lo Privado.

Pero así también su nombre lo dice: aporta puntos escenciales, básicos, y primarios que uno debe seguir si uno quiere que sus clases sean fáciles de usar y rehusar. Fíjate que de éste Principio es que luego se desprende los conceptos de Herencia, Acoplamiento y Cohesión.

Por supuesto que hay formas de llegar a esos puntos, y es justamente como con estos 6 conceptos dieron origen a los GRAPS, luego con éstos surgen los GoF y con todo esto ya aparecieron los demás patrones que se fueron especializando.

 

OJO: ten presente que Template , Decorator, Adapter, Interceptor que parecieran tener en escencia un "denominador común" no están pensados para lo mismo.

 

Cada patrón toma el principio, y "acomoda" los porcentajes de cada cosa, que junto con Bajo Acoplamiento (GRAPS), Alta Cohesión (GRAPS) y en menor medida Variaciones Protegidas (GRAPS) propone un diseño molde para una necesidad puntual, para un problema en un contexto puntual. Ninguno viola el Principio Abierto/Cerrado, simplemente proponen un estado de equilibrio adecuado para ese caso.

 

El problema está en quedarnos que nuestros diseños son estáticos y no volveremos a tocarlos nunca más. Ahí es cuando aparecen los problemas... tenemos clases ya hechas, necesitamos redefinir partes, ampliar, ¡hasta quitar! Pero claro: tocar algo puede ser un parto... y la máxima de "si lo anda no lo toques" nos dice que es mejor no hacerlo. Los Patrones tienen sus límites, uno se siente tentado a recurrir vías alternativas... Los Helpers pueden ayudar.

Pero no hay que dejarnos llevar demasiado porque es muy fácil luego en que tenemos que volver a meter mano... vuelve a crecer... y de nuevo la casa está en desorden.

Es muy fácil caer en ese ciclo y sentirnos que nunca llegamos a sentirnos conformes y que nos estamos perdiendo de algo... De igual manera es también fácil caer en el otro lado: Nos fuimos por los cerros de Úbeda y nos mandamos un diseño que al final sobredimensionamos la cosa.

 

¡Lo dice alguien que se mueve por todos los extremos que se encuentren! :p  Y después me pregunto porque es que existe la Reingeniería *-)  ;)  8o|

 

Saludos,


  • 1

#13 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 12 abril 2016 - 08:22

Jaja hace poco pusieron esto en G+, no puedo evitar postearlo. Esta en tema che!

 

SingleResponsibilityPrinciple2_71060858.


  • 0

#14 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.301 mensajes
  • LocationArgentina

Escrito 13 abril 2016 - 09:01

Jaja. Viste Agustín... ahora mi analogía con la Navaja no parece ser tan errada ;) 

Llevo unos cuantos años explorando algunos conceptos OO, y aún me falta mucho por dominar (sobre todo varios patrones de diseño) pero si hay algo de lo que estoy seguro es que estamos llenos de navajas y en cualquier momento nos podemos cortar.

 

Saludos,


  • 0

#15 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 14 abril 2016 - 03:54

Bueno..en principio muchas gracias a todos los que respondieron.. que me dieron su opinión al respecto.

 

Y cuando tenga algo mas o menos desarrolla en POO voy a hacer un  nuevo hilo.. también para mostrar mi habilidad y recibir criticas constructivas obviamente..

 

Saludos..


  • 0

#16 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.301 mensajes
  • LocationArgentina

Escrito 14 abril 2016 - 04:54

Bueno..en principio muchas gracias a todos los que respondieron.. que me dieron su opinión al respecto.

 

Y cuando tenga algo mas o menos desarrolla en POO voy a hacer un  nuevo hilo.. también para mostrar mi habilidad y recibir criticas constructivas obviamente..

 

Saludos..

 

Perdón si el hilo tomó un giro de ideas y se fue a un debate.

Así es el foro, acá se debate en muchas cosas.

 

Como podrás notar en el mundo del Software hay muchas areas grises y los "DEPENDE" como suele llamar un compañero del foro se presentan muy seguido. La POO tiene algo que la hace exquisita, y es que dos diseños distintos pueden responder a un mismo requerimiento y no necesariamente eso significa que alguno de ellos esté mal. Asi que no te castigues demasiado por si tu diseño te parece débil, o si tienes muchas, (o pocas) clases.

Es natural, y sano, cuestionarse si vamos haciendo bien o mal las cosas. Lo que no es sano en absoluto es dejar que esto se nos venga encima.

 

Saludos,


  • 0

#17 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 14 abril 2016 - 05:00

Perdón si el hilo tomó un giro de ideas y se fue a un debate.
Así es el foro, acá se debate en muchas cosas.

Como podrás notar en el mundo del Software hay muchas areas grises y los "DEPENDE" como suele llamar un compañero del foro se presentan muy seguido. La POO tiene algo que la hace exquisita, y es que dos diseños distintos pueden responder a un mismo requerimiento y no necesariamente eso significa que alguno de ellos esté mal. Asi que no te castigues demasiado por si tu diseño te parece débil, o si tienes muchas, (o pocas) clases.
Es natural, y sano, cuestionarse si vamos haciendo bien o mal las cosas. Lo que no es sano en absoluto es dejar que esto se nos venga encima.

Saludos,

Si. De hecho he practicado poo en php.. pero quiero tener un sistema listo para venderselo a un negocio que lo necesite. Y si..soy medio novato asi que voy a publicar sin miedo a que me corrijan..

Enviado desde mi SM-G530M mediante Tapatalk
  • 0




IP.Board spam blocked by CleanTalk.