Imaginez que votre client souhaite avoir la possibilité d'ajouter une nouvelle propriété (par exemple, la couleur) au produit dans son eshop dans son CMS.
Au lieu d'avoir des propriétés comme champs:
class Car extends Product {
protected String type;
protected int seats;
}
Vous finiriez probablement par faire quelque chose comme:
class Product {
protected String productName;
protected Map<String, Property> properties;
}
class Property {
protected String name;
protected String value;
}
C'est-à-dire, créer son propre système de types par-dessus celui existant. Il me semble que cela pourrait être considéré comme créant une langue spécifique à un domaine, ou non?
Cette approche est-elle un modèle de conception connu? Résoudriez-vous le problème différemment? Je sais qu'il existe des langues dans lesquelles je peux ajouter un champ lors de l'exécution, mais qu'en est-il de la base de données? Souhaitez-vous plutôt ajouter / modifier des colonnes ou utiliser quelque chose comme indiqué ci-dessus?
Merci pour votre temps :).
Réponses:
Toutes nos félicitations! Vous venez de faire le tour du globe du système de langage / type de programmation, arrivant de l'autre côté du monde d'où vous êtes parti. Vous venez d'atterrir à la frontière du langage dynamique / terre objet basé sur des prototypes!
De nombreux langages dynamiques (par exemple JavaScript, PHP, Python) permettent d'étendre ou de modifier les propriétés des objets lors de l'exécution.
La forme extrême de ceci est un langage basé sur un prototype comme Self ou JavaScript. Ils n'ont pas de cours à proprement parler. Vous pouvez faire des choses qui ressemblent à une programmation basée sur des classes, orientée objet avec héritage, mais les règles sont considérablement assouplies par rapport à des langages basés sur des classes mieux définis comme Java et C #.
Des langages comme PHP et Python vivent au milieu. Ils ont des systèmes basés sur des classes régulières et idiomatiques. Mais les attributs d'objet peuvent être ajoutés, modifiés ou supprimés au moment de l'exécution - bien qu'avec certaines restrictions (comme «sauf pour les types intégrés») que vous ne trouvez pas en JavaScript.
Le gros compromis de ce dynamisme est la performance. Oubliez à quel point la langue est typée fortement ou faiblement, ou à quel point elle peut être compilée en code machine. Les objets dynamiques doivent être représentés comme des cartes / dictionnaires flexibles, plutôt que de simples structures. Cela ajoute une surcharge à chaque accès aux objets. Certains programmes se donnent beaucoup de mal pour réduire ce surcoût (par exemple avec une affectation de kwarg fantôme et des classes basées sur des slots en Python), mais le surcoût supplémentaire est généralement à la hauteur du cours et du prix d'admission.
Pour revenir à votre conception, vous greffez la possibilité d'avoir des propriétés dynamiques sur un sous-ensemble de vos classes. A
Product
peut avoir des attributs variables; vraisemblablement unInvoice
ou unOrder
serait et ne pourrait pas. Ce n'est pas une mauvaise façon de procéder. Il vous donne la possibilité de varier là où vous en avez besoin, tout en restant dans un système de langage et de type strict et discipliné. En revanche, vous êtes responsable de la gestion de ces propriétés flexibles, et vous devrez probablement le faire via des mécanismes qui semblent légèrement différents des attributs plus natifs.p.prop('tensile_strength')
plutôt quep.tensile_strength
, par exemple, etp.set_prop('tensile_strength', 104.4)
plutôt quep.tensile_strength = 104.4
. Mais j'ai travaillé avec et construit de nombreux programmes en Pascal, Ada, C, Java et même des langages dynamiques qui utilisaient exactement un tel accès getter-setter pour les types d'attributs non standard; l'approche est clairement réalisable.D'ailleurs, cette tension entre les types statiques et un monde très varié est extrêmement courante. Un problème analogue est souvent observé lors de la conception d'un schéma de base de données, en particulier pour les magasins de données relationnelles et pré-relationnelles. Parfois, il est traité en créant des "super-lignes" qui contiennent suffisamment de flexibilité pour contenir ou définir l'union de toutes les variations imaginées, puis en remplissant toutes les données qui entrent dans ces champs. Le WordPress
wp_posts
tableau , par exemple, a des champs commecomment_count
,ping_status
,post_parent
etpost_date_gmt
qui ne sont intéressants que dans certaines circonstances, et que , dans la pratique vont souvent en blanc. Une autre approche est une table normalisée très disponible commewp_options
, tout comme votreProperty
classe. Bien qu'il nécessite une gestion plus explicite, les éléments qu'il contient sont rarement vides. Les bases de données orientées objet et documentaires (par exemple MongoDB) ont souvent plus de facilité à gérer les options changeantes, car elles peuvent créer et définir des attributs à peu près à volonté.la source
J'aime la question, mes deux cents:
Vos deux approches sont radicalement différentes:
En C ++, beaucoup utiliseraient une carte std :: map de boost :: variant pour obtenir un mélange des deux.
Disgression: Notez que certains langages, tels que C #, permettent la création dynamique de types. Ce qui pourrait être une bonne solution pour le problème général de l'ajout dynamique de membres. Cependant, "modifier / ajouter" des types après la compilation endommage le système de types lui-même et rend vos types "modifiés" presque inutiles (par exemple, comment accéderiez-vous à ces propriétés ajoutées, puisque vous ne savez même pas qu'elles existent? La seule manière raisonnable serait être une réflexion systématique sur chaque objet ... se terminant par un langage dynamique pur _ vous pouvez vous référer au mot-clé .NET 'dynamique')
la source
La création d'un type à l'exécution semble beaucoup plus compliquée que la simple création d'une couche d'abstraction. Il est très courant de créer une abstraction pour découpler des systèmes.
Permettez-moi de montrer un exemple de ma pratique. La bourse de Moscou a le noyau commercial appelé Plaza2 avec l'API du commerçant. Les traders écrivent leurs programmes pour travailler avec des données financières. Le problème est que ces données sont très énormes, complexes et très exposées aux changements. Il peut changer après l'introduction d'un nouveau produit financier ou la modification de grilles de compensation. La nature des changements futurs n'est pas prévisible. Littéralement, cela peut changer tous les jours et les mauvais programmeurs devraient modifier le code et publier une nouvelle version, et les traders en colère devraient réviser leurs systèmes.
La décision évidente est de cacher tout l'enfer financier derrière une abstraction. Ils ont utilisé l'abstraction de tables SQL bien connue. La plus grande partie de leur cœur peut fonctionner avec n'importe quel schéma valide, tout comme le logiciel du commerçant peut analyser dynamiquement le schéma et savoir s'il est compatible avec leur système.
Pour revenir à votre exemple, il est normal de créer un langage abstrait devant une logique. Il peut s'agir de «propriété», de «table», de «message» ou même de langage humain, mais faites attention aux inconvénients de cette approche:
la source
En XML et HTML, ce seraient les attributs d'un nœud / élément. Je les ai également entendus appelés propriétés étendues, paires nom / valeur et paramètres.
C'est ainsi que je résoudrais le problème, oui.
Une base de données serait comme Java, dans certains sens. En pesudo-sql:
Cela correspondrait à Java
Notez qu'il n'y a pas besoin d'une classe Property, car la carte stocke le nom comme clé.
J'ai essayé la colonne add / alter et c'était un cauchemar. Cela peut être fait, mais les choses se désynchronisaient et je n'ai jamais réussi à bien fonctionner. La structure de tableau que j'ai décrite ci-dessus a été beaucoup plus efficace. Si vous avez besoin de faire des recherches et par ordre de, envisagez d' utiliser une table d' attributs pour chaque type de données (
date_attributes
,currency_attributes
, etc.) ou en ajoutant quelques - unes des propriétés que les bonnes vieilles colonnes de base de données dans la table des produits. Les rapports sont souvent beaucoup plus faciles à écrire sur les colonnes de la base de données que sur les sous-tables.la source