[POO] Comment modéliser des concepts cycliques sans dépendance cyclique ?

a marqué ce sujet comme résolu.
Auteur du sujet

Bonjour,

Je suis en train de développer un petit simulateur de circuits logiques.

L’entité de plus haut niveau est le circuit, constitué de composants. Ces composants peuvent être des composants élémentaires built-in (sources de niveau logique, portes logiques), ou être eux-mêmes définis par un sous-circuit. Cela permet de définir de nouveaux composants plus complexes et de les réutiliser.

J’ai donc une dépendance cyclique dans les concepts : un circuit est défini par une série de composants, un composant peut être défini par un circuit.

Comment modéliser ça en programmation orientée objet ? Les dépendances cycliques posent des problèmes, mais je ne vois pas comment casser celle-ci.

Merci, bonne soirée.

+0 -0
Auteur du sujet

J’ai cru comprendre que c’est un mauvais design connu en POO, qui peut et doit généralement être évité.

https://en.wikipedia.org/wiki/Acyclic_dependencies_principle

Je ne connais pas toutes les raisons pour cela.

Mais déjà, par ex en Python, cela implique un import cyclique, ce qui ne semble pas faisable de manière propre.

Je me pose peut-être des contraintes qui n’ont pas lieu d’être, je ne sais pas. Je suis venu ici pour avoir éventuellement l’avis de développeurs habitués à la modélisation objet, car ça doit être un problème récurrent je pense.

+0 -0

Salut,

Que dirais-tu de quelque chose du genre (code écrit rapidement et non testé).

class One:
    def evaluate(self):
        return True
    
class Zero:
    def evaluate(self):
        return False

class Or:
    def __init__(self, c1, c2):
        self.c1 = c1
        self.c2 = c2
    
    def evaluate(self):
        return self.c1.evaluate() or self.c2.evaluate()
        
class And:
    def __init__(self, c1, c2):
        self.c1 = c1
        self.c2 = c2
        
    def evaluate(self):
        return self.c1.evaluate() and self.c2.evaluate()

one = One()
zero = Zero()

print(And(one, zero).evaluate())

Nos circuits sont des instances d’une classe qui possède une méthode evaluate qui renvoie un booléen (duck-typing power).

Édité par Karnaj

Assez des salamis, je passe au jambon — Je fais un carnage si ce car nage car je nage, moi, Karnaj ! — Le comble pour un professeur de mathématique ? Mourir dans l’exercice de ses fonctions.

+0 -0

Je pense qu’il y a deux choses différentes dans cette histoire.

La première est la dépendance cyclique entre packages. C’est sûr que c’est à éviter dans la plupart du temps, puisque ça peut être signe qu’un package devrait être redécoupé autrement.

La deuxième histoire est la définition d'objets récursifs. Tu ne peux pas passer à côté et ce n’est pas un problème, au contraire. Par exemple, un arbre est une structure de données composée d’un nœud-racine reliés à des nœuds qui constituent eux-mêmes des arbres. Dans ce cas-là, il n’y a pas de dépendances récursives entre composants, puisqu’il s’agit du même composant, qui ne dépend donc que de lui-même (un nœud en l’occurrence).

Ta modélisation d’un circuit tombe exactement dans le cas de l’arbre, comme toutes les structures hiérarchiques. Tu es obligé de définir un circuit comme étant composé de sous-circuits. Pour ce qui est des composants, j’ai juste l’impression qu’il s’agit d’un sous-type de circuits.

Tu peux probablement jeter un oeil au trucs type VHDL ou les netlists pour voir comment on peut décrire un circuit (notamment de manière hiérarchique). Ça ne te dira pas comment programmer, mais ça donne une idée de la modélisation.

+4 -0

Personnellement, je ne comprend pas le problème car je ne vois pas ce que cet héritage a de cyclique. En effet, pour moi, un circuit est un composant (j’en veux pour preuve qu’un circuit intégré est considéré comme un composant) mais un composant n’est pas nécessairement un circuit. Ainsi, on aurait cette hiérarchie

          Composant
              |
              |
   +----------+---------+---------...
   |          |         |
   |          |         |
Circuit  Transistor Résistance

et un cicuit contiendrait un container de composants. Peut-être que mon approche est mauvaise et que je ne comprend pas le problème mais c’est de cette façon que je perçois la situation.

+1 -0

Je rejoins Aabu sur l’idée que le récursif n’est pas une mauvaise chose quand la structure est justifiée.

En revanche, tu peux tout de même casser le côté récursif. Tout simplement en créant un tableau d’index de tes objets et en ajoutant l’index du tableau dans chacun de ses enfants.

class Circuit {
  constructor (nom) {
    this.index = null;
    this.nom = nom;
    this.type = 'Circuit';
    this.parent = null;
  }
}

class Composant {
  constructor (nom) {
    this.index = null;
    this.nom = nom;
    this.type = 'Composant';
    this.parent = null;
  }
}

let indexes = [];

let circuit = new Circuit('Mon premier circuit');
circuit.index = indexes.length;
indexes.push(circuit);

let comp = new Composant('Mon premier composant enfant de circuit');
comp.parent = circuit.index;
comp.index = indexes.length;
indexes.push(comp);

Bien entendu ce travail pour qu’il soit plus propre, doit être orchestré par une classe tenant pour rôle l’ajout et la gestion de tes objets à sa pile. Un avantage de cette méthode, c’est que tu peux dénombrer le nombre d’objets dont tu disposes à l’instant T. Et si tu as besoin d’un export au format JSON par exemple, tu ne seras pas bloqué par l’aspect récursif ; tu peux très bien exporter puis importer le tableau d’index sans perdre une seule information.

Tant de choses, tant de vies, tant de possibilités.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte