Je recherche des modèles ou des conseils architecturaux pour une fonctionnalité à venir que je conçois. Fondamentalement, c'est une fonction d'exportation avec plusieurs cibles d'exportation, et je cherche à trouver un moyen de la rendre suffisamment générique où le branchement de nouvelles cibles d'exportation ne nécessite pas beaucoup de changements de base. Par cibles d'exportation, je fais simplement référence à différents types de sortie, qu'il s'agisse de PDF, de présentations PowerPoint, de documents Word, de RSS, etc. J'ai un ensemble de données de base, qui est représenté en JSON et XML. Ces données sont utilisées pour construire des images (en utilisant n'importe quel nombre ou type d'exportation [par exemple, PNG, JPG, GIF, etc.), des graphiques, des représentations textuelles, des tableaux, etc.
J'essaie de trouver un moyen d'abstraire tout le rendu et la mise en page dans une sorte de moteur de rendu ou de mise en page qui gère l'ajout d'autres cibles d'exportation. Toute aide / suggestion / ressource sur la manière d'aborder cela serait grandement appréciée. Merci d'avance.
Pour une représentation imagée de ce que j'essaie de réaliser.
la source
Réponses:
Pour moi, la voie à suivre serait des interfaces et une usine. Celui qui renvoie des références aux interfaces derrière lesquelles diverses classes peuvent se cacher. Les classes qui effectuent le travail de grognement réel doivent toutes être enregistrées auprès de la fabrique afin qu'elle sache quelle classe instancier en fonction d'un ensemble de paramètres.
Remarque: au lieu d'interfaces, vous pouvez également utiliser des classes de base abstraites, mais l'inconvénient est que pour les langages à héritage unique, il vous limite à une seule classe de base.
Le code est en syntaxe Delphi (Pascal) car c'est le langage que je connais le mieux.
Une fois que toutes les classes d'implémentation sont enregistrées auprès de la fabrique, vous devriez pouvoir demander une référence d'interface à une instance d'une telle classe. Par exemple:
doit renvoyer une référence IReader à une instance de TXMLReader; une référence IWriter à une instance de TPowerPointWriter et une référence IRepresentation à une instance de THTMLTable.
Maintenant, tout ce que le moteur de rendu doit faire, c'est tout lier:
L'interface IReader devrait fournir des méthodes pour lire les données nécessaires aux implémenteurs IRepresentation pour construire la représentation des données. De même, IRepresentation doit fournir les méthodes dont les implémenteurs IWriter ont besoin pour exporter la représentation des données au format de fichier d'exportation demandé.
En supposant que les données de vos fichiers sont de nature tabulaire, IReader et ses interfaces de support pourraient ressembler à:
Itérer sur une table serait alors une question de
Comme les représentations peuvent être des images, des graphiques et des textes, les représentations IR auraient probablement des méthodes similaires à IReader pour parcourir une table construite et des méthodes pour obtenir les images et les graphiques, par exemple sous la forme d'un flux d'octets. Il appartiendrait aux implémenteurs IWriter d'encoder les valeurs de la table et les octets image / graphique requis par la cible d'exportation.
la source
Bien que je convienne que plus d'informations sont nécessaires pour penser à une architecture, le moyen le plus simple de créer différents types d'objets qui se comportent de la même manière (c'est-à-dire qu'ils généreront tous une sortie) est d'utiliser le modèle d'usine. Plus d'infos ici
la source
Vous pourriez vous retrouver avec quelque chose comme ça.
Les deux usines s'articulent autour de:
1 - pour convertir le type d'entrée (Json / XML) en une implémentation concrète de la façon de convertir ces données en image / graphique
2 - Une deuxième usine pour décider comment rendre la sortie en un document Word / Document PDF
Le polymorphisme utilise une interface commune pour toutes les données rendues. Ainsi, une image / table peut être déplacée comme une interface facile.
1 - Factory pour convertir les données JSON / XML en une implémentation concrète:
L'usine ci-dessous vous permet de convertir les données xml ou les données Json en type de béton correct.
Les implémentations concrètes font tout le travail lourd de conversion des données dans le type approprié. Ils convertissent également les données vers l'interface IConvertedData, qui est utilisée pour le polymorphisme.
Vous pouvez ajouter ces implémentations si nécessaire, à mesure que votre code se développe.
L'interface IConvertedData vous permet de passer un seul type dans la phase suivante: REMARQUE: vous ne pouvez pas renvoyer de vides ici. Il peut s'agir d'un octet [] pour les images ou d'un document OpenXml pour le WordDocument. Ajustez si nécessaire.
Polymorphisme:
Ceci est utilisé pour convertir les données en type de sortie approprié. c'est-à-dire que le rendu au format PDF des données d'image peut être différent des données d'image de rendu pour PowerPoint.
2 - Usine pour décider du format de sortie:
Chaque implémentation concrète expose une méthode courante qui masque la façon dont l'exportation est renvoyée aux implémentations IConvertedData
Un exemple de client pour tout cela serait:
la source
Nous avons résolu un problème similaire ici: https://ergebnisse.zensus2011.de/?locale=en Là, nous avons principalement des "tableaux" et des "graphiques" à exporter dans différents formats: pdf, excel, web. Notre idée était de spécifier chaque objet à rendre comme une propre classe Java avec des interfaces pour créer et lire ces classes. Dans votre cas, il y aurait 2 implémentations pour chaque objet pour la création (xml, json) et 4 implémentations pour le rendu (lecture).
Exemple: Vous aurez besoin de certaines classes pour les tables: Table de classe (gère la structure de la table, la validation et le contenu) Interface CreateTable (fournit les données du tableau, les cellules, les étendues, le contenu) Interface ReadTable (getters pour toutes les données)
Vous n'avez probablement pas besoin des interfaces (ou d'une seule) mais je pense que cela fournit toujours un bon découplage particulièrement utile pour les tests.
la source
Je pense que ce que vous cherchez, c'est le modèle de stratégie . Vous disposez d'une variété de classes pour produire les données dans le format souhaité, et vous choisissez simplement celle qui convient lors de l'exécution. L'ajout d'un nouveau format doit être aussi simple que l'ajout d'une autre classe qui implémente l'interface requise. Je l'ai fait souvent en Java en utilisant Spring pour simplement maintenir une carte de convertisseurs, indexée par le type de format.
Comme d'autres l'ont mentionné, cela se fait généralement en faisant en sorte que toutes les classes implémentent la même interface (ou descendent de la même classe de base) et en choisissant l'implémentation via une usine.
la source