La mise en œuvre correcte de la propriété de tous les objets qui sont égaux

scristalli:

Le problème

Envisager une mise en œuvre d'un graphique, SampleGraph<N>. Envisager une mise en œuvre des nœuds du graphe, Node extends N, prépondérants correctement hashCodeet equalsde refléter l' égalité logique entre deux nœuds.

Maintenant, disons que nous voulons ajouter une propriété p à un nœud. Une telle propriété est liée à des instances logiques d'un noeud, par exemple pour Node n1, n2, n1.equals(n2)implique p ( n1) = p ( n2)

Si j'ajoute simplement la propriété comme un champ de la Nodeclasse, ce qui est arrivé à moi:

  • Je définis de Node n1, n2telle sorte que , n1.equals(n2)maisn1 != n2
  • Ajouter n1et n2à un graphique: n1lors de l' insertion du noeud logique, et n2lors du référencement pour le noeud lors de l' insertion des bords. Le graphique stocke les deux cas.
  • Plus tard, je récupère le nœud du graphe ( n1est retourné) et définissez la propriété p sur elle une certaine valeur. Plus tard, je traverse toutes les arêtes du graphe, et récupérer le nœud d'un d'entre eux ( n2est retourné). La propriété p est pas définie, ce qui provoque une erreur logique dans mon modèle.

Pour résumer, le comportement actuel :

graph.addNode(n1) // n1 is added
graph.addEdge(n2,nOther) // graph stores n2
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n2 is returned

La question

Tous les énoncés suivants semblent raisonnables pour moi. Aucun d'entre eux me convainc entièrement sur les autres, donc je suis à la recherche de lignes directrices sur les pratiques fondées sur les canons de génie logiciel.

S1 - La mise en œuvre du graphique est faible. Lors de l' ajout d' un nœud, le graphique doit toujours vérifier en interne si elle a une instance du même noeud ( equalsEquivaut à true) mémorisé. Si oui, par exemple doit toujours être la seule référence utilisée par le graphique.

graph.addNode(n1) // n1 is added
graph.addEdge(n2,nOther) // graph internally checks that n2.equals(n1), doesn't store n2
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n1 is returned

S2 - En supposant que le se comporte de graphe comme dans S1 est une erreur. Le programmeur doit veiller à ce que toujours la même instance d'un nœud est passé au graphique.

graph.addNode(n1) // n1 is added
graph.addEdge(n1,nOther) // the programmer uses n1 every time he refers to the node
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n1 is returned

S3 - La propriété est pas mise en œuvre de la bonne façon. Il devrait être une information qui est externe à la classe Node. Une collection, comme un HashMap<N, Property>, fonctionnerait très bien, le traitement de différentes instances comme le même objet sur la base hashCode.

HashMap<N, Property> properties;

graph.addNode(n1) // n1 is added
graph.addEdge(n2,nOther) // graph stores n2
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n2 is returned

// get the property. Difference in instances does not matter
properties.get(n1)
properties.get(n2) //same property is returned

S4 - Comme S3, mais nous pourrions cacher à l'intérieur de la mise en œuvre Node, de cette façon:

class Node {
  private static HashMap<N, Property> properties;

  public Property getProperty() {
    return properties.get(this);
  }
}

Modifier : extraits de code ajouté pour le comportement actuel et les solutions provisoires suivantes Stephen C de réponse . Pour clarifier, l'ensemble de l' exemple vient d'utiliser une véritable structure de données de graphique à partir d' un projet Java open source.

Stephen C:

Pour moi, il revient de choisir entre des API avec abstraction forte ou faible.

  • Si vous choisissez l' abstraction forte, l'API se cacher le fait que les Nodeobjets ont l' identité, et je les canoniser quand ils sont ajoutés à la SimpleGraph.

  • Si vous choisissez l' abstraction faible, l'API supposerait que les Nodeobjets ont l' identité, et il appartiendrait à l'appelant de les canoniser avant de les ajouter à la SimpleGraph.

Les deux approches conduisent à différents contrats API et nécessitent différentes stratégies de mise en œuvre. Le choix est susceptible d'avoir des répercussions sur la performance ... si cela est important.

Ensuite, il y a des détails plus fins de la conception de l'API qui peuvent ou peuvent ne pas correspondre à votre cas d'utilisation spécifique pour les graphiques.

Le point est que vous devez faire le choix.

(Ce bit est comme décider d'utiliser les collections Listinterface et son modèle propre, par rapport à la mise en œuvre de votre propre structure de données de liste chaînée afin que vous puissiez efficacement « épissage » 2 listes ensemble. Approche soit pourrait être correcte, en fonction des besoins de votre application .)

Notez que vous habituellement pouvez faire un choix, bien que le choix peut être difficile. Par exemple, si vous utilisez une API conçue par quelqu'un d' autre:

  • Vous pouvez choisir d'utiliser tel quel. (Suck it up!)
  • Vous pouvez choisir d' essayer d' influencer la conception. (Bonne chance!)
  • Vous pouvez choisir de passer à une API différente; soit un autre fournisseur.
  • Vous pouvez choisir de bifurquer l'API et l'ajuster à vos propres besoins (ou les préférences si c'est ce que cela est sur le point)
  • Vous pouvez choisir de concevoir et mettre en œuvre votre propre API à partir de zéro.

Et si vous vraiment n'avez pas le choix, cette question est sans objet. Il suffit d' utiliser l'API.


Si cela est une API open source , alors vous n'avez probablement pas le choix d'obtenir les concepteurs de changer. API importantes remises en état ont tendance à créer beaucoup de travail pour d' autres personnes; à savoir les nombreux autres projets qui dépendent de l'API. Une équipe designer API responsable / conception prend en compte. Ou bien ils trouvent qu'ils perdent la pertinence parce que leurs API obtiennent la réputation d'être instable.

Alors ... si vous visez à influencer une conception API open source existant ... « car vous pensez qu'ils le font de manière incorrecte (pour une définition incorrecte) ... vous êtes probablement mieux « bifurquer » l'API et faire face aux conséquences.


Et enfin, si vous cherchez des conseils « meilleures pratiques », sachez qu'il n'y a pas de meilleures pratiques . Et ce n'est pas seulement une question philosophique. C'est pourquoi vous aurez vissé si vous allez demander / la recherche de conseils « meilleures pratiques », puis suivez.


En note: avez-vous déjà demandé pourquoi les bibliothèques de classes Java standard et Android ne proposent aucune API graphique à usage général ou mises en œuvre? Et pourquoi ils ont si longtemps à apparaître dans les bibliothèques 3ème partie (version Goyave 20.0)?

La réponse est qu'il n'y a pas de consensus sur ce qu'une telle API devrait être. Il y a trop de cas d'usage conflictuel et ensembles d'exigences.

Je suppose que tu aimes

Origine http://43.154.161.224:23101/article/api/json?id=207777&siteId=1
conseillé
Classement