La correcta aplicación de la propiedad de todos los objetos que son iguales

scristalli:

El problema

Considere una implementación de un gráfico, SampleGraph<N>. Considere una implementación de los nodos del grafo, Node extends N, anulando correctamente hashCodey equalspara reflejar la igualdad lógica entre dos nodos.

Ahora, supongamos que queremos añadir alguna propiedad P a un nodo. Tal propiedad está obligado a instancias lógicas de un nodo, es decir, para Node n1, n2, n1.equals(n2)implica p ( n1) = p ( n2)

Si sólo tiene que añadir la propiedad como un campo de la Nodeclase, esto ha sucedido a mí:

  • Defino Node n1, n2tal que n1.equals(n2)aunquen1 != n2
  • Agrego n1y n2a un gráfico: n1cuando se inserta el nodo lógico, y n2cuando se hace referencia al nodo durante la inserción de los bordes. El gráfico almacena ambos casos.
  • Más tarde, puedo recuperar el nodo en el gráfico ( n1se devuelve) y establezca la propiedad p en él a un cierto valor. Más tarde, recorro todos los bordes de la gráfica, y recuperar el nodo a partir de (uno de ellos n2se devuelve). La propiedad p no está establecido, causando un error lógico en mi modelo.

En resumen, el comportamiento actual :

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 pregunta

Todas las siguientes afirmaciones me parecen razonables. Ninguno de ellos me convence totalmente a través de los demás, por lo que estoy buscando guías de buenas prácticas sobre la base de los cánones de ingeniería de software.

S1 - La aplicación gráfica es pobre. Tras la adición de un nodo, el gráfico debe comprobar siempre internamente si tiene una instancia de un mismo nodo ( equalsse considera verdadero) memorizado. Si es así, tal instancia debe ser siempre la única referencia utilizada por el gráfico.

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 - Suponiendo que se comporta el gráfico como en S1 es un error. El programador debe tener cuidado de que siempre la misma instancia de un nodo se pasa a la gráfica.

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 propiedad no se lleva a cabo de la manera correcta. Debe ser una información que es externo a la clase Node. Una colección, tales como HashMap<N, Property>, funcionaría bien, el tratamiento de diferentes instancias como el mismo objeto basado en 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 - Igual que el S3, pero que podrían ocultar el interior de la aplicación Node, de esta manera:

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

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

Edit : añadido fragmentos de código para el comportamiento actual y soluciones tentativas siguiente Stephen C 's respuesta . Para aclarar, todo el ejemplo proviene del uso de una estructura de datos gráfico real de un proyecto de código abierto de Java.

Stephen C:

Por mi mente, se trata de elegir entre la API con la abstracción fuerte o débil.

  • Si elige la abstracción fuerte, la API podría ocultar el hecho de que Nodelos objetos tienen identidad, y se canonicalize ellos cuando se agregan al SimpleGraph.

  • Si elige la abstracción débil, la API asumiría que Nodelos objetos tienen identidad, y sería hasta la persona que llama a canonicalize antes de añadirlos a la SimpleGraph.

Los dos enfoques conducen a diferentes contratos de API y requieren diferentes estrategias de implementación. La elección es probable que tenga consecuencias en el rendimiento ... si eso es significativo.

Luego están los detalles más finos del diseño de API que pueden o no coincidir con su caso de uso específico para los gráficos.

El punto es que usted necesita para tomar la decisión.

(Esta un poco es como la decisión de utilizar las colecciones Listde interfaz y su modelo limpio, en comparación con la implementación de su propia estructura de datos de lista enlazada de manera que pueda eficientemente "empalme" 2 listas juntas. Enfoque O podría ser correcta, dependiendo de los requerimientos de su aplicación .)

Tenga en cuenta que por lo general puede tomar una decisión, aunque la elección puede ser difícil. Por ejemplo, si está utilizando una API diseñada por otra persona:

  • Usted puede optar por usarlo tal cual. (Suck it up!)
  • Usted puede optar por tratar de influir en el diseño. (¡Buena suerte!)
  • Puede optar por cambiar a una API diferente; es decir, un proveedor diferente.
  • Usted puede elegir para bifurcar la API y ajustarlo a sus necesidades o preferencias (si esto es lo que se trata)
  • Usted puede elegir para diseñar y poner en práctica su propia API desde cero.

Y si realmente no tiene una opción, entonces esta pregunta es discutible. Sólo tiene que utilizar la API.


Si se trata de una API de código abierto, entonces es probable que no tiene la opción de conseguir los diseñadores para cambiarlo. Reacondicionamientos API significativos tienen una tendencia de crear una gran cantidad de trabajo para otras personas; es decir, los muchos otros proyectos que dependen de la API. Una API equipo de diseño / diseño responsable tiene esto en cuenta. O bien se encuentran con que pierden relevancia porque sus APIs obtener una reputación de ser inestable.

Así que ... si está destinado a influir en un diseño de la API de código abierto existentes ... 'porque usted piensa que lo están haciendo de forma incorrecta (por alguna definición incorrecta) ... usted es probablemente mejor de 'bifurcación' de la API y frente a las consecuencias.


Y, por último, si usted está buscando consejo "mejores prácticas", tenga en cuenta que no existen mejores prácticas . Y esto no es sólo una cuestión filosófica. Esto es por qué usted conseguirá atornillado si vas pidiendo / en busca de asesoramiento "mejores prácticas", y luego sigue.


Como una nota al pie: ¿se ha preguntado por qué el Java y bibliotecas de clases estándar de Android no ofrecen ninguna API de gráficos o implementaciones de propósito general? Y por qué tomaron tanto tiempo para aparecer en las bibliotecas 3 ª parte (guayaba versión 20.0)?

La respuesta es que no hay un consenso sobre lo que una API tales como deben ser. Hay demasiados casos de uso en conflicto y series de requisitos.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=207779&siteId=1
Recomendado
Clasificación