Design Pattern: Adaptative Object Model

Cela faisait bien longtemps que l’on avait pas parler design pattern et aujourd’hui nous allons traiter de l’un de mes préférés: l’Adaptative Object Model [4] ou plus simplement appeler le pattern Type-Instance

Lorsque l’on étudie les designs patterns il faut dire que l’on voit surtout les patterns d’écriture comme le Templates Methods [1], les structuraux (comme le composite [2]) ou comportementaux comme le Visiteur [3].

En effet, il s’agit d’un pattern d’architecture intégrant a la fois des aspects structurantes mais aussi comportementales et pour dire c’est normal car il intègre conjointement deux patterns:

  • le pattern TypeObject
  • le pattern Property

Mais avant de rentrer dans le détail (car pour le coup on va vraiment entrer dans le détail pour ce pattern AOM), regardons a quel besoin il répond.

Méta-architecture

Une méta-architecture? hein mais c’est quoi ça encore? Une méta-architecture est une architecture capable de s’adapter dynamiquement en cours de fonctionnement a de nouveaux besoins utilisateur.

Pour ce faire l’approche classique est de construire une application qui permet de redéfinir son fonctionnement pendant son exécution. L’application va alors se constituer a la fois d’un outil permettant de définir différentes modèles et d’un outil permettant l’exploitation de ces définitions sans passer par la case compilation ou redéploiement.

Ainsi un designer va pouvoir penser de nouveau usage et les formaliser au sein du système, et une fois ceux ci validés, un utilisateur du domaine pour lequel se rapporte l’outil, va pouvoir exploiter ces nouvelles fonctionnalités.

L’intérêt de l’utilisation des méta-architectures ne se limite pas a la capacité d’étendre un domaine fonctionnel mais aussi de permettre d’en définir de multiples. Par exemple sur la base d’un outil gérant les concepts Entity-Relation, on peut imaginer définir un domaine de définition pour des cartes avec des villes et des routes ou un domaine de définition pour de la modalisation objet (simpliste) avec des objets et leur relations ou encore un domaine pour établir un réseau social, avec des gens et leur relations.

Pattern TypeObject

Limites des approches classiques

Pour réaliser ce genre d’approche, dans une conception classique d’un système logiciel, on s’appuie classiquement sur l’utilisation de la généricité mise en œuvre grâce à l’héritage permettant de sous classer des concepts depuis un contexte générique vers un concept spécifique.

Ainsi, on peut manipuler différents types d’entité ou de relation propre a leur domaine spécifique, nous pourrions ajouter également les villages, d’autres types de relation objet par exemple. Le problème de cette approche est qu’elle est ne permet pas l’ajout de nouveaux type d’entité sans passer par la case compilation.

Pour s’affranchir de cela, le concept objet par les mécanismes d’instanciation permettrai de définir autant de type d’entités ou de relations que souhaités cependant de cette manière, nous perdons alors la notion de sous-type et ce que cela peut entrainer en terme de complexité de gestion des instances (devoir ajouter une données membres pour caractériser le type, devoir faire des vérifications systématique sur cette donnée membre pour savoir ce que l’on manipule, ou encore jouer avec des interfaces, etc…) en somme une démarche laborieuse!

La réification des concepts

Quand on y regarde, il ne nous manque rien dans les deux exemples précédents, seulement, il nous faudrait les avantages des deux mécanismes en même temps.

Pour cela, on va utiliser un autre mécanisme de conception logiciel: la réification. Ce mot semble un peu barbare mais il ne signifie que « transformer sous forme d’objet quelque chose ». En substance, cela signifie donner de la substance a un élément qui potentiellement manque de concrétisation. Le cas typique est la réification d’une relation.

Par exemple une roue est en relation avec le moteur, mais cela peut être limitatif, en réifiant cette relation via l’arbre de transmission, on affine la modélisation de cette liaison en la concrétisant.

Dans le cas de la modélisation d’une méta-architecture, alors on va réifier les concepts de type et d’instance nous amenant (enfin) au pattern TypeObject

Ce pattern parait bêtement simpliste avec juste ses deux concepts. Cependant en réifiant ces concepts, il va alors être possible de construire au sein de la mème exécution deux cycle de vie différents: celui des types et celui des instances sans …. compilation et pouvoir donc mettre en œuvre les caractéristiques d’une méta-architecture. Si on l’applique a notre exemple de l’entity/relation:

Ici donc si on déclare les concepts de Ville en instanciant un EntityType et de route sous la forme d’une RelationType alors dans un second temps, il sera possible de declarer les villes d’Amiens, Douai, Arras en instanciant la classe Entity mais en relation avec le EntityType Ville.

Pattern Property

C’est bien tout ça! Mais les propriétés comment dans une définition, on va déclarer des propriétés qui devront être présent dans les entités? Et bien de la même manière par réification!

L’idée ici est donc simple, au lieu de contenir directement des données membres, on va créer une classe property dont l’entité en sera responsable.

Square Model

Maintenant il reste a fusionner ces deux patterns de manière a permettre la définition de PropertyType applicable sur des Property en découplant les notions de type pour l’un et de value pour l’autre. Cela nous amène au square model suivant:

Que l’on pourra instancier de façon suivante:

Pour ceux qui auront vu plus loin que leur lecture, bien sur l’application du pattern Property permet d’externaliser les données membres de la même manière qu’un pattern stratégie permettra d’externaliser les comportements dans une logique similaire.

Implémentation et exemple

Pour illustrer tout ca on va en faire une petite implémentation en python.J’en avais fait une déjà il y a une bonne quinzaine d’année en Java pour ceux que ça intéresse [5].

On va se définir une classe de base pour indexer nos objets ainsi que leur donner une sérialisation sous format JSON car on terminera par définir une petite interface Rest dessus pour manipuler notre application.

class IndexedObject:
    objectId = 0

    def __init__(self, name):
        IndexedObject.objectId += 1
        self.id = IndexedObject.objectId
        self.name = name

    def __getitem__(self, name):
        return self.__getattribute__(name)

    def __setitem__(self, name, valeur):
        return self.__setattr__(name, valeur)

    def __delitem__(self):
        return ","

    def toDict(self):
        obj_dict = {
            "__class__": self.__class__.__name__,
            "__module__": self.__module__
        }
        obj_dict.update(self.__dict__)
        return obj_dict

Suite a cela, on va définir nos classes de base Type et Instance:

class Type(IndexedObject):

    def __init__(self, name):
        IndexedObject.__init__(self, name)
        self.instances = []

    def buildInstance(self, name):
        pass

    def toDict(self):
        obj_dict = IndexedObject.toDict(self)

        obj_dict.update({
            "instances": [object.toDict() for object in self.instances]
        })
        return obj_dict
class Instance(IndexedObject):

    def __init__(self, name, mm):
        IndexedObject.__init__(self, name)
        self.mm = mm

    def toDict(self):
        obj_dict = IndexedObject.toDict(self)

        obj_dict.update({
            "mm": self.mm.name
        })
        return obj_dict

A partir de la, nous allons implémenter le pattern ERA (Entity, Relation, Attribut) en tant que Metamodele et Modele.

MétaModele

class MetaModel(Type):

    def __init__(self, name):
        Type.__init__(self, name)
        self.entitiesType = []
        self.relationsType = []

    def buildInstance(self, name):
        system = Model(name, self)
        self.instances.append(system)
        return system

    def buildEntityType(self, name):
        entityType = EntityType(name)
        self.entitiesType.append(entityType)
        return entityType

    def buildRelationType(self, name, src, dst):
        relationType = RelationType(name, src, dst)
        self.relationsType.append(relationType)
        return relationType

    def toDict(self):
        obj_dict = Type.toDict(self)

        obj_dict.update({
            "entitiesType": [object.toDict() for object in self.entitiesType],
            "relationsType": [object.toDict() for object in self.relationsType]
        })
        return obj_dict


class EntityType(Type):

    def __init__(self, name):
        Type.__init__(self, name)
        self.propertiesType = []

    def buildPropertyType(self, name, valueType):
        propertyType = PropertyType(name, valueType)
        self.propertiesType.append(propertyType)
        return propertyType

    def buildInstance(self, name):
        newInstance = Entity(name, self)
        self.instances.append(newInstance)
        return newInstance

    def toDict(self):
        obj_dict = Type.toDict(self)

        obj_dict.update({
            "propertiesType": [object.toDict() for object in self.propertiesType]
        })
        return obj_dict


class PropertyType(Type):

    def __init__(self, name, valueType):
        Type.__init__(self, name)
        self.valueType = valueType

    def buildInstance(self, name, value):
        newInstance = Property(name, self, value)
        self.instances.append(newInstance)
        return newInstance

    def toDict(self):
        obj_dict = Type.toDict(self)

        obj_dict.update({
            "valueType": self.valueType
        })
        return obj_dict


class RelationType(Type):

    def __init__(self, name, srcEntityType, dstEntityType):
        Type.__init__(self, name)
        self.srcEntityType = srcEntityType
        self.dstEntityType = dstEntityType

    def buildInstance(self, name, srcEntityTypeName, src, dstEntityTypeName, dst):
        srcType = [object for object in self.srcEntityType if object.name == srcEntityTypeName][0]
        dstType = [object for object in self.dstEntityType if object.name == dstEntityTypeName][0]

        srcInstance = [object for object in srcType.instances if object.name == src][0]
        dstInstance = [object for object in dstType.instances if object.name == dst][0]

        relation = Relation(name, srcInstance, dstInstance, self)
        self.instances.append(relation)
        return relation

    def toDict(self):
        obj_dict = Type.toDict(self)

        obj_dict.update({
            "srcEntityType": [object.toDict() for object in self.srcEntityType],
            "dstEntityType": [object.toDict() for object in self.dstEntityType]
        })
        return obj_dict

Modèle

class Model(Instance):

    def __init__(self, name, mm):
        Instance.__init__(self, name, mm)
        self.entities = []
        self.relations = []

    def toDict(self):
        obj_dict = Instance.toDict(self)

        obj_dict.update({
            "entities": [object.toDict() for object in self.entities],
            "relations": [object.toDict() for object in self.relations]
        })
        return obj_dict


class Entity(Instance):

    def __init__(self, name, mm):
        Instance.__init__(self, name, mm)
        self.properties = []

    def toDict(self):
        obj_dict = Instance.toDict(self)

        obj_dict.update({
            "properties": [object.toDict() for object in self.properties]
        })
        return obj_dict

class Property(Instance):

    def __init__(self, name, mm, value):
        Instance.__init__(self, name, mm)
        self.value = value

    def toDict(self):
        obj_dict = Instance.toDict(self)
        obj_dict.update({
            "value": self.value
        })
        return obj_dict


class Relation(Instance):

    def __init__(self, name, src, dst, mm):
        Instance.__init__(self, name, mm)
        self.src = src
        self.dst = dst

    def toDict(self):
        obj_dict = Instance.toDict(self)
        obj_dict.update({
            "src": self.src.toDict(),
            "dst": self.dst.toDict()
        })
        return obj_dict

Controller Rest

Voila nous voila donc avec notre framework de fait, on va maintenant ajouter différents endpoint Rest avec Flask (je m’embête pas la, je met tout le fichier pour le détail mais pour ceux voulant l’intégralité des sources, vous les trouverez dans le dépôt git du blog [6]).

#!flask/bin/python
import json

from flask import Flask, jsonify, request
from flask_cors import CORS

from meta_fmk import MetaModel

app = Flask(__name__)
CORS(app)

root = [

]


################################################################################## M2
@app.route('/m2', methods=['GET'])  # OK
def get_m2():
    return jsonify([m2.toDict() for m2 in root])


@app.route('/m2/<string:m2Name>', methods=['GET'])  # OK
def get_m2_by_name(m2Name):
    return jsonify([m2.toDict() for m2 in root if m2.name == m2Name][0])


@app.route('/m2', methods=['POST'])  # OK
def post_m2_by_name():
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    meta = MetaModel(json_response["name"])
    root.append(meta)
    return jsonify(meta.id)


################################################################################## M2 PropertyType

@app.route('/m2/<string:m2Name>/entityType/<string:entityTypeName>/propertyType', methods=['GET'])  # OK
def get_propertyTypes(m2Name, entityTypeName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    entityType = [entityType for entityType in m2.entitiesType if entityType.name == entityTypeName][0]
    return jsonify([propertyType.toDict() for propertyType in entityType.propertiesType])


@app.route('/m2/<string:m2Name>/entityType/<string:entityTypeName>/propertyType', methods=['POST'])  # OK
def post_propertyTypes(m2Name, entityTypeName):
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    entityType = [entityType for entityType in m2.entitiesType if entityType.name == entityTypeName][0]
    propertyType = entityType.buildPropertyType(json_response["name"], json_response["valueType"])
    return jsonify(propertyType.id)


################################################################################## M2 EntityType
@app.route('/m2/<string:m2Name>/entityType', methods=['GET'])  # OK
def get_entityType(m2Name):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    return jsonify([entityType.toDict() for entityType in m2.entitiesType])


@app.route('/m2/<string:m2Name>/entityType/<string:entityTypeName>', methods=['GET'])  # OK
def get_entityType_with_name(m2Name, entityTypeName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    return jsonify([entityType.toDict() for entityType in m2.entitiesType if entityType.name == entityTypeName][0])


@app.route('/m2/<string:m2Name>/entityType/<string:entityTypeName>/entity', methods=['GET'])  # OK
def get_entityType_instances_with_name(m2Name, entityTypeName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    entityType = [entityType for entityType in m2.entitiesType if entityType.name == entityTypeName][0]
    return jsonify([entity.toDict() for entity in entityType.instances])


@app.route('/m2/<string:m2Name>/entityType/<string:entityTypeName>/entity/<string:entityName>', methods=['GET'])  # OK
def get_entityType_instance_with_name(m2Name, entityTypeName, entityName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    entityType = [entityType for entityType in m2.entitiesType if entityType.name == entityTypeName][0]
    return jsonify([entity.toDict() for entity in entityType.instances if entity.name == entityName][0])


@app.route('/m2/<string:m2Name>/entityType', methods=['POST'])  # OK
def post_entityType_with_name(m2Name):
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    meta = m2.buildEntityType(json_response["name"])
    return jsonify(meta.id)


################################################################################## M2 RelationType
@app.route('/m2/<string:m2Name>/relationType', methods=['GET'])  # OK
def get_relationType(m2Name):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    return jsonify([relationType.toDict() for relationType in m2.relationsType])


@app.route('/m2/<string:m2Name>/relationType/<string:relationTypeName>', methods=['GET'])  # OK
def get_relationType_with_name(m2Name, relationTypeName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    return jsonify(
        [relationType.toDict() for relationType in m2.relationsType if relationType.name == relationTypeName][0])


@app.route('/m2/<string:m2Name>/relationType/<string:relationTypeName>/relation', methods=['GET'])  # OK
def get_relationType_instances_with_name(m2Name, relationTypeName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    relationType = [relationType for relationType in m2.relationsType if relationType.name == relationTypeName][0]
    return jsonify([relation.toDict() for relation in relationType.instances])


@app.route('/m2/<string:m2Name>/relationType/<string:relationTypeName>/relation/<string:relationName>',
           methods=['GET'])  # OK
def get_relationType_instance_with_name(m2Name, relationTypeName, relationName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    relationType = [relationType for relationType in m2.relationsType if relationType.name == relationTypeName][0]
    return jsonify(
        [relation.toDict() for relation in relationType.instances if relation.name == relationName][0])


@app.route('/m2/<string:m2Name>/relationType', methods=['POST'])  # OK
def post_relationType_with_name(m2Name):
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    srcEntityType = [srcEntityType for srcEntityType in m2.entitiesType if
                     srcEntityType.name in json_response["srcEntityType"]]
    dstEntityType = [dstEntityType for dstEntityType in m2.entitiesType if
                     dstEntityType.name in json_response["dstEntityType"]]

    meta = m2.buildRelationType(json_response["name"], srcEntityType, dstEntityType)
    return jsonify(meta.id)


################################################################################## M


@app.route('/m2/<string:m2Name>/m', methods=['GET'])  # OK
def get_m2_instance(m2Name):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    return jsonify([model.toDict() for model in m2.instances])


@app.route('/m2/<string:m2Name>/m/<string:mName>', methods=['GET'])  # OK
def get_m2_instance_with_name(m2Name, mName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    return jsonify(model.toDict())


@app.route('/m2/<string:m2Name>/m', methods=['POST'])  # OK
def post_m_instance_with_name(m2Name):
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = m2.buildInstance(json_response["name"])
    return jsonify(model.id)


################################################################################## M Entity


@app.route('/m2/<string:m2Name>/m/<string:mName>/entity', methods=['GET'])  # OK
def get_entities(m2Name, mName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    return jsonify([entity.toDict() for entity in model.entities])


@app.route('/m2/<string:m2Name>/m/<string:mName>/entity/<string:entityName>', methods=['GET'])  # OK
def get_entity_with_name(m2Name, mName, entityName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    entity = [entity for entity in model.entities if entity.name == entityName][0]
    return jsonify(entity.toDict())


@app.route('/m2/<string:m2Name>/m/<string:mName>/entityType/<string:entityTypeName>/entity', methods=['POST'])  # OK
def post_entity_with_name(m2Name, mName, entityTypeName):
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    entityType = [entityType for entityType in m2.entitiesType if entityType.name == entityTypeName][0]
    entity = entityType.buildInstance(json_response["name"])
    model.entities.append(entity)
    return jsonify(entity.id)


################################################################################## M Property


@app.route('/m2/<string:m2Name>/m/<string:mName>/entity/<string:entityName>/property', methods=['GET'])  # OK
def get_properties(m2Name, mName, entityName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    entity = [entity for entity in model.entities if entity.name == entityName][0]
    return jsonify([property.toDict() for property in entity.properties])


@app.route(
    '/m2/<string:m2Name>/m/<string:mName>/entity/<string:entityName>/propertyType/<string:propertyTypeName>/property',
    methods=['POST'])  # OK
def post_property(m2Name, mName, entityName, propertyTypeName):
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    entity = [entity for entity in model.entities if entity.name == entityName][0]
    propertyType = [propertyType for propertyType in entity.mm.propertiesType if propertyType.name == propertyTypeName][0]
    property = propertyType.buildInstance(json_response["name"], json_response["value"])
    entity.properties.append(property)
    return jsonify(property.id)


################################################################################## M Relation


@app.route('/m2/<string:m2Name>/m/<string:mName>/relation', methods=['GET'])  # OK
def get_relations(m2Name, mName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    return jsonify([relation.toDict() for relation in model.relations])


@app.route('/m2/<string:m2Name>/m/<string:mName>/relation/<string:relationName>', methods=['GET'])  # OK
def get_relation_with_name(m2Name, mName, relationName):
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    relation = [relation for relation in model.relations if relation.name == relationName][0]
    return jsonify(relation.toDict())


@app.route('/m2/<string:m2Name>/m/<string:mName>/relationType/<string:relationTypeName>/relation',
           methods=['POST'])  # OK
def post_relation_with_name(m2Name, mName, relationTypeName):
    print("REQUEST:" + str(request.data))
    json_response = json.loads(request.data)
    m2 = [m2 for m2 in root if m2.name == m2Name][0]
    model = [model for model in m2.instances if model.name == mName][0]
    relationType = [relationType for relationType in m2.relationsType if relationType.name == relationTypeName][0]
    relation = relationType.buildInstance(json_response["name"], json_response["srcType"], json_response["src"],
                                          json_response["dstType"], json_response["dst"])
    model.relations.append(relation)
    return jsonify(relation.id)


def main():
    app.run(debug=True, port=5001, host='0.0.0.0')


if __name__ == '__main__':
    main()

Packaging

Maintenant que l’on a notre application python de prête, on va la packager dans un conteneur docker pour nous faciliter la vie:

FROM collonvtom/python-flask:latest

run apk add --no-cache curl

COPY . /
CMD python3 controler.py  

Jeux de tests

Enfin on va se faire un jeux de données JSON a injecter avec quelques curls:

#!/bin/bash

BASE_URL="http://localhost:5001"

addElement()
{
  curl --request POST "$BASE_URL/$1" -H "Content-Type: application/json" -H "Accept: application/json" -d "$2"
}

addElement m2 '{ "name" : "MyMM" }'
addElement m2/MyMM/entityType '{ "name" : "MyEntityType1" }'
addElement m2/MyMM/entityType '{ "name" : "MyEntityType2" }'
addElement m2/MyMM/entityType '{ "name" : "MyEntityType3" }'

addElement m2/MyMM/entityType/MyEntityType1/propertyType '{ "name" : "MyPropertyType1", "valueType" : "Integer" }'
#
addElement m2/MyMM/relationType '{ "name" : "MyrelationType1", "srcEntityType": [ "MyEntityType1", "MyEntityType3" ], "dstEntityType" : [ "MyEntityType2" ] }'
addElement m2/MyMM/relationType '{ "name" : "MyrelationType2" ,"srcEntityType": [ "MyEntityType2" ], "dstEntityType" : [ "MyEntityType1" ] }'
#
#
addElement m2/MyMM/m '{ "name" : "MyModel" }'
#
addElement m2/MyMM/m/MyModel/entityType/MyEntityType1/entity '{ "name" : "MyEntity1" }'
addElement m2/MyMM/m/MyModel/entityType/MyEntityType2/entity '{ "name" : "MyEntity2" }'
addElement m2/MyMM/m/MyModel/entityType/MyEntityType3/entity '{ "name" : "MyEntity3" }'
addElement m2/MyMM/m/MyModel/entityType/MyEntityType1/entity '{ "name" : "MyEntity4" }'
addElement m2/MyMM/m/MyModel/entityType/MyEntityType2/entity '{ "name" : "MyEntity5" }'
#

addElement m2/MyMM/m/MyModel/entity/MyEntity1/propertyType/MyPropertyType1/property '{ "name" : "MyProperty1", "value" : "1" }'
#
#
addElement m2/MyMM/m/MyModel/relationType/MyrelationType1/relation '{ "name" : "MyRelation1", "src": "MyEntity1", "srcType": "MyEntityType1", "dst" : "MyEntity2", "dstType" : "MyEntityType2"}'
addElement m2/MyMM/m/MyModel/relationType/MyrelationType1/relation '{ "name" : "MyRelation2", "src": "MyEntity3", "srcType": "MyEntityType3", "dst" : "MyEntity5", "dstType" : "MyEntityType2"}'
addElement m2/MyMM/m/MyModel/relationType/MyrelationType2/relation '{ "name" : "MyRelation3", "src": "MyEntity5", "srcType": "MyEntityType2", "dst" : "MyEntity4", "dstType" : "MyEntityType1"}'
addElement m2/MyMM/m/MyModel/relationType/MyrelationType1/relation '{ "name" : "MyRelation4", "src": "MyEntity3", "srcType": "MyEntityType3", "dst" : "MyEntity2", "dstType" : "MyEntityType2"}'

Suite a cela, je vous laisse jouer avec en utilisant un postman afin de récupérer les données ou faire quelques POST supplémentaires afin de nourrir soit le modèle, soit d’ajouter un nouveau métamodèle avec vos concepts et de l’utiliser. Enjoy comme on dit!?

A noter que cette implémentation est très « light », de nombreuses contraintes ne sont pas implémenté et mériterai de l’être. Contrairement au framework Java dont je parlais précédemment [5], qui est probablement mieux implémenté (enfin dans mon souvenir….)

Conclusions

Voila, nous venons de voir l’un des patterns les plus que je connaisse, il permet de concevoir des méta-architectures et de fournir un haut niveau de customisation tout en abordant des concepts plutôt simple.

Attention par contre cette simplicité de façade est toute relative une fois les mains dans l’implémentation car le niveau d’abstraction va vous faire des nœuds au cerveau pour correctement suivre les schéma d’instanciation. De plus il faut bien garder en tête que deux cycle de vie sont actifs en même temps, celui des Type et celui des instances nécessitant de bien gérer les contraintes et leur évolution en cas de changement de définition.

Malgré ces difficultés ce pattern reste vraiment fun a mettre en œuvre et surtout très pratique pour casser certaines problématiques lié justement à la gestion de la généricité.

Références

Un commentaire sur “Design Pattern: Adaptative Object Model

Laisser un commentaire