Imagine que su cliente quiere tener la posibilidad de agregar una nueva propiedad (por ejemplo, color) al producto en su tienda virtual 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, crear un sistema de tipo propio encima del existente. Me parece que esto podría verse como la creación de un lenguaje específico de dominio, ¿o no?
¿Es este enfoque 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? ¿Prefieres agregar / modificar columnas o usar algo como se muestra arriba?
Gracias por tu tiempo :).
Respuestas:
¡Felicidades! Acaba de dar la vuelta al mundo del lenguaje de programación / sistema de tipos, llegando al otro lado del mundo desde donde partió. ¡Acabas de aterrizar en el borde del lenguaje dinámico / tierra de objetos basados en prototipos!
Muchos lenguajes dinámicos (por ejemplo, JavaScript, PHP, Python) permiten ampliar 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. No tienen clases, estrictamente hablando. Puede hacer cosas que parecen una 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 objeto se pueden agregar, cambiar o eliminar en tiempo de ejecución, aunque con algunas restricciones (como "excepto para los tipos integrados") que no se encuentran en JavaScript.
La gran compensación para este dinamismo es el rendimiento. Olvídese de cuán fuerte o débilmente tipeado es el idioma, o qué tan bien puede compilarse en código máquina. Los objetos dinámicos deben representarse como mapas / diccionarios flexibles, en lugar de estructuras simples. Esto agrega sobrecarga a cada acceso a objetos. Algunos programas hacen todo lo posible para reducir esta sobrecarga (por ejemplo, con la asignación fantasma kwarg y las clases basadas en slots en Python), pero la sobrecarga adicional generalmente es igual al curso y al precio de admisión.
Volviendo a su diseño, está injertando la capacidad de tener propiedades dinámicas en un subconjunto de sus clases. A
Product
puede tener atributos variables; presumiblemente unInvoice
o unOrder
podría y no podría. No es un mal camino a seguir. Le brinda la flexibilidad de tener variaciones donde las necesite, mientras se mantiene 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 dep.tensile_strength
, por ejemplo, y enp.set_prop('tensile_strength', 104.4)
lugar dep.tensile_strength = 104.4
. Pero trabajé y construí muchos programas en Pascal, Ada, C, Java e incluso en lenguajes dinámicos que usaban exactamente ese acceso getter-setter para tipos de atributos no estándar; El enfoque es claramente viable.Por cierto, esta tensión entre los tipos estáticos y un mundo muy variado es extremadamente común. A menudo se ve un problema análogo al diseñar el esquema de la base de datos, especialmente para los almacenes de datos relacionales y pre-relacionales. A veces se trata creando "super filas" que contienen suficiente flexibilidad para contener o definir la unión de todas las variaciones imaginadas, y luego rellenar cualquier dato que ingrese en esos campos. El WordPress
wp_posts
mesa , por ejemplo, tiene campos comocomment_count
,ping_status
,post_parent
ypost_date_gmt
que sólo son interesantes en algunas circunstancias, y que en la práctica a menudo queda en blanco. Otro enfoque es una tabla normalizada , muy libre,wp_options
como suProperty
clase. Si bien requiere una administración más explícita, los elementos en él rara vez están en blanco. Las bases de datos orientadas a objetos y documentos (por ejemplo, MongoDB) a menudo tienen más facilidad para manejar las opciones cambiantes, porque pueden crear y establecer atributos prácticamente a voluntad.fuente
Me gusta la pregunta, mis dos centavos:
Sus dos enfoques son radicalmente diferentes:
En C ++, muchos usarían un std :: map of boost :: variant para lograr una combinación de ambos.
Disgresión: Tenga en cuenta que algunos lenguajes, 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, "modificar / agregar" tipos después de la compilación corrompe el sistema de tipos en sí mismo y hace 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 forma razonable sería ser un reflejo sistemático sobre cada objeto ... terminando con un lenguaje dinámico puro _ puede referirse a la palabra clave 'dinámica' .NET)
fuente
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 mostrarte un ejemplo de mi práctica. El intercambio de Moscú tiene el núcleo comercial llamado Plaza2 con API de operador. Los comerciantes escriben sus programas para trabajar con datos financieros. El problema es que estos datos son muy grandes, complejos y altamente expuestos a cambios. Puede cambiar después de la introducción de un nuevo producto financiero o cambios en los roles de compensación. La naturaleza de los cambios futuros no se puede predecir. Literalmente, puede cambiar todos los días y los programadores pobres deberían editar el código y lanzar una nueva versión, y los comerciantes enojados deberían revisar sus sistemas.
La decisión obvia es ocultar todo el infierno financiero detrás de una abstracción. Han utilizado abstracciones de tablas SQL bien conocidas. La mayor parte de su núcleo puede funcionar con cualquier esquema válido, al igual que el software del operador 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 alguna lógica. Podría ser "propiedad", "tabla", "mensaje" o incluso lenguaje humano, pero preste atención a los inconvenientes de este enfoque:
fuente
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.
Así es como resolvería el problema, sí.
Una base de datos sería como Java, en algunos sentidos. En pesudo-sql:
Esto correspondería al Java
Tenga en cuenta que no hay necesidad de una clase de Propiedad, ya que el Mapa almacena el nombre como la clave.
He intentado agregar / modificar columna, y fue una pesadilla. Se puede hacer, pero las cosas no se sincronizaban y nunca conseguí que funcionara bien. La estructura de la tabla que describí anteriormente ha sido mucho más exitosa. Si lo que necesita hacer búsquedas y por fin de, considerar el uso de una tabla de atributos para cada tipo de datos (
date_attributes
,currency_attributes
, etc.) o la adición de algunas de las propiedades como buenos viejos columnas de base de datos en la tabla productos. Los informes son a menudo mucho más fáciles de escribir en columnas de bases de datos que en subtablas.fuente