Agregar campo a la clase en tiempo de ejecución - patrón de diseño

15

Imagine que su cliente desea tener la posibilidad de agregar nuevas propiedades (por ejemplo, color) al producto en su tienda electrónica en su CMS.

En lugar de tener propiedades como campos:

class Car extends Product {
   protected String type;
   protected int seats;
}

Probablemente terminarías haciendo algo como:

class Product {
   protected String productName;
   protected Map<String, Property> properties;
}

class Property {
   protected String name;
   protected String value;
}

Es decir, creando un sistema de tipo propio sobre el existente. Me parece que esto podría ser visto como la creación de un idioma específico del dominio, o no podría?

¿Este enfoque es un patrón de diseño conocido? ¿Resolverías el problema de manera diferente? Sé que hay idiomas en los que puedo agregar un campo en tiempo de ejecución, pero ¿qué pasa con la base de datos? ¿Prefiere agregar / alterar columnas o usar algo como se muestra arriba?

Gracias por tu tiempo :).

    
pregunta Filip 18.04.2014 - 02:02
fuente

4 respuestas

4

¡Felicitaciones! Acaba de circunnavegar el lenguaje de programación / sistema de tipo globo, llegando al otro lado del mundo desde donde partió. ¡Acaba de aterrizar en el borde del lenguaje dinámico / de objetos basados en prototipos!

Muchos idiomas dinámicos (por ejemplo, JavaScript, PHP, Python) permiten extender o cambiar las propiedades de los objetos en tiempo de ejecución.

La forma extrema de esto es un lenguaje basado en prototipos como Self o JavaScript. Ellos No tengo clases, estrictamente hablando. Puede hacer cosas que se parecen a la programación orientada a objetos, basada en clases, con herencia, pero las reglas son mucho más relajadas en comparación con lenguajes más definidos y basados en clases como Java y C #.

Langauges como PHP y Python viven en el medio. Tienen sistemas regulares, idiomáticos basados en clases. Pero los atributos de los objetos se pueden agregar, cambiar o eliminar en tiempo de ejecución, aunque con algunas restricciones (como "excepto para los tipos incorporados") que no se encuentran en JavaScript.

La gran compensación para este dinamismo es el rendimiento. Olvídese de qué tan fuerte o débilmente se escribe el idioma, o qué tan bien puede compilarse en código de máquina. Los objetos dinámicos deben representarse como mapas / diccionarios flexibles, en lugar de estructuras simples. Esto agrega sobrecarga a cada acceso de objeto. Algunos programas hacen todo lo posible para reducir esta sobrecarga (por ejemplo, con la asignación fantasma kwarg y las clases basadas en tragamonedas en Python), pero la sobrecarga adicional es generalmente igual a la del curso y el precio de admisión.

Volviendo a su diseño, está incorporando la capacidad de tener propiedades dinámicas en un subconjunto de sus clases. Un Product puede tener atributos variables; presumiblemente, un Invoice o un Order podrían y no podrían. No es una mala manera de ir Le brinda la flexibilidad de tener la variación donde la necesita, mientras permanece en un lenguaje estricto y disciplinado y un sistema de tipos. En el lado negativo, usted es responsable de administrar esas propiedades flexibles, y probablemente tendrá que hacerlo a través de mecanismos que se ven ligeramente diferentes de los atributos más nativos. p.prop('tensile_strength') en lugar de p.tensile_strength , por ejemplo, y p.set_prop('tensile_strength', 104.4) en lugar de p.tensile_strength = 104.4 . Sin embargo, he trabajado con y desarrollado muchos programas en Pascal, Ada, C, Java e incluso en lenguajes dinámicos que usaban exactamente el acceso de los que establecen los tipos de atributos para tipos de atributos no estándar; el enfoque es claramente viable.

Por cierto, esta tensión entre tipos estáticos y un mundo muy variado es extremadamente común. Un problema análogo se ve a menudo cuando se diseña un esquema de base de datos, especialmente para almacenes de datos relacionales y pre-relacionales. A veces se trata creando "súper filas" que contienen suficiente flexibilidad para contener o definir la unión de todas las variaciones imaginadas, y luego rellenar los datos que vienen en esos campos. La tabla de WordPress wp_posts , por ejemplo, tiene campos como comment_count , ping_status , post_parent y post_date_gmt que solo son interesantes en algunas circunstancias, y que en la práctica a menudo se quedan en blanco. Otro enfoque es una tabla de repuesto normalizada como wp_options , muy parecida a su clase Property . Si bien requiere una administración más explícita, los elementos en ella rara vez están en blanco. Las bases de datos orientadas a objetos y documentos (por ejemplo, MongoDB) a menudo tienen un tiempo más fácil para cambiar las opciones, ya que pueden crear y establecer atributos a voluntad.

    
respondido por el Jonathan Eunice 16.08.2014 - 16:50
fuente
0

Me gusta la pregunta, mis dos centavos:

Sus dos enfoques son radicalmente diferentes:

  • El primero es OO y está fuertemente tipado, pero no es extensible
  • El segundo está mal escrito (la cadena encapsula cualquier cosa)

En C ++, muchos usarían un std :: map de boost :: variant para lograr una mezcla de ambos.

Disgresión: Tenga en cuenta que algunos idiomas, como C #, permiten la creación dinámica de tipos. Lo que podría ser una buena solución para el problema general de agregar miembros dinámicamente. Sin embargo, los tipos de "modificación / adición" después de la compilación dañan el propio sistema de tipos y hacen que sus tipos "modificados" sean casi inútiles (por ejemplo, ¿cómo accedería a esas propiedades agregadas, ya que ni siquiera sabe que existen? La única manera razonable Sea una reflexión sistemática sobre cada objeto ... que termina con un lenguaje dinámico puro _ puede referirse a la palabra clave '.NET' dinámica '

    
respondido por el quantdev 18.04.2014 - 05:12
fuente
0

Crear un tipo en tiempo de ejecución suena mucho más complicado que simplemente crear una capa de abstracción. Es muy común crear una abstracción para desacoplar sistemas.

Déjame mostrar un ejemplo de mi práctica. intercambio de Moscú tiene el núcleo de comercio llamado Plaza2 con API del comerciante. Los comerciantes escriben sus programas para trabajar con datos financieros. El problema es que estos datos son muy grandes, complejos y están muy expuestos a los cambios. Puede cambiar después de la introducción de un nuevo producto financiero o cambios de compensación. No se puede predecir la naturaleza de los cambios futuros. Literalmente, puede cambiar todos los días y los programadores deficientes deben editar el código y lanzar una nueva versión, y los comerciantes enojados deben revisar sus sistemas.

La decisión obvia es ocultar todo infierno financiero detrás de una abstracción. Han utilizado la abstracción de tablas SQL bien conocida. La mayor parte de su núcleo puede funcionar con cualquier esquema válido, al igual que el software del comerciante puede analizar dinámicamente el esquema y averiguar si es compatible con su sistema.

Volviendo a su ejemplo, es normal crear un lenguaje abstracto frente a cierta lógica. Puede ser "propiedad", "tabla", "mensaje" o incluso lenguaje humano, pero preste atención a los inconvenientes de este enfoque:

  • Más código para analizar y validar (y más tiempo fuera del curso). Todo lo que el compilador hizo por ti con la escritura estática debes hacer. en el tiempo de ejecución.
  • Más documentación de mensajes, tablas u otras primitivas. Todos la complejidad va del código a algún tipo de esquema o standart. Aquí está Un ejemplo del esquema del infierno financiero mencionado anteriormente: enlace (docenas de páginas de mesas)
respondido por el astef 23.05.2014 - 12:29
fuente
0
  

¿Este enfoque es un patrón de diseño conocido?

En XML y HTML, estos serían los atributos de un nodo / elemento. También los he escuchado, denominados propiedades extendidas, pares de nombre / valor y parámetros.

  

¿Resolverías el problema de manera diferente?

Así es como resolvería el problema, sí.

  

Sé que hay idiomas en los que puedo agregar un campo en tiempo de ejecución, pero ¿qué pasa con la base de datos?

Una base de datos sería como Java, en algunos sentidos. En pesudo-sql:

TABLE products
(
    product_name VARCHAR(50),
    product_id INTEGER AUTOINCREMENT
)

TABLE attributes
(
    product_id INTEGER,
    name VARCHAR(50),
    value VARCHAR(2000)
)

Esto correspondería a Java

class Product {
   protected String productName;
   protected Map<String, String> properties;
}

Tenga en cuenta que no hay necesidad de una clase de propiedad, ya que el mapa almacena el nombre como la clave.

  

¿Preferiría agregar / alterar columnas o utilizar algo como se muestra arriba?

He intentado agregar / alterar la columna, y fue una pesadilla. Se puede hacer, pero las cosas se desincronizaron y nunca funcionó bien. La estructura de la tabla que describí anteriormente ha sido mucho más exitosa. Si necesita realizar búsquedas y ordenar por, considere usar una tabla de atributos para cada tipo de datos ( date_attributes , currency_attributes , etc.) o agregar algunas de las propiedades como columnas de bases de datos antiguas en la tabla de productos. Los informes suelen ser mucho más fáciles de escribir en las columnas de la base de datos que en las sub tablas.     

respondido por el Guy Schalnat 09.07.2014 - 06:39
fuente

Lea otras preguntas en las etiquetas