2010-05-25 15 views
5

Me gustaría poder especificar que las variables de miembro de un objeto son inmutables una vez que el objeto ha sido "inicializado", lo que para mí significa después de haber sido inyectado con cualquier dependencia y haber realizado cualquier otra operación de inicialización que solo puede realizar después de DI.Inmutabilidad después de inyección de dependencia, inicialización

¿Existen idiomas que satisfagan mi interés, que formalizan la DI, la inicialización y la inmutabilidad de soporte de esta manera? Tal vez es tonto hacerlos parte de un idioma; tal vez no. No estoy seguro.

Hoy programo en Java, pero no puedo usar "final" casi tanto como me gustaría, porque esas fases ocurren después de que el constructor haya terminado la ejecución. ¿Algún consejo sobre cómo obtener lo que quiero con Java? Creo que podría hacer que mis objetos implementen una clase base para que esas fases sucedan antes de que el constructor finalice, o use aspectos para hacer lo mismo.

¿Pensamientos?

Respuesta

3

supongo depende de lo que quieras de la inmutabilidad. Si desea la seguridad garantizada de subprocesos (donde todo debe declararse final, incluidas las dependencias), entonces creo que las inyecciones de fábrica, constructor o constructor son sus únicas opciones.

Sin embargo, si solo desea la inmutabilidad del estado, entonces declarar las variables de estado definitivas debería ser suficiente. Incluso la clase de cadena inmutable tiene un campo mutable en su implementación (una memoria caché del valor de código hash). Siempre que su código garantice que una instancia no esté disponible sin inyección, todo debería estar bien.

+0

Solo quiero que quede claro qué miembros son mutables y cuáles no. Extraño, pero nunca pensé en cómo la inyección del colocador es incompatible con el estado inmutable. Bueno, no estaba pensando en eso cuando escribí la pregunta, al menos :-) – Ladlestein

0

En Java, si está utilizando métodos de mutador para hacer su configuración de todos modos, es bastante barato (aunque también bastante feo para mí) agregar lógica para evitar alteraciones una vez que el objeto se inicializa.

public void setMyProperty(String newValue) { 
    checkInitialized(); 
    myProperty = newValue; 
} 

public void checkInitialized() { 
    if (initialized) { 
     throw new IllegalStateException("Setter called after initialization"); 
    } 
} 

En el mejor de los casos esto está dando un control dinámico. No le da ningún comentario estático sobre lo que ya habría tenido.

4

Hay dos formas principales de la producción de objetos inmutables:

  1. utilizar el patrón constructor/fábrica - el constructor puede ser mutable, pero los objetos que crea son inmutables, por lo general implementado con campos finales. También puede combinar los dos, por lo que el objeto en sí se usa para crear nuevas instancias, generalmente a través de métodos "mutatores" que cambian el estado en una nueva instancia separada. El FactoryBean de Spring es un ejemplo de esto.

  2. crea una subclase MutableObject, que mantiene un indicador para el estado mutable. Todos sus mutadores verifican el estado mutable antes de realizar cualquier cambio: si el objeto se ha establecido como inmutable, el control arroja una excepción; de lo contrario, el cambio continúa.

El primer enfoque es bastante centrado en primavera, ya que requiere la implementación de una interfaz específica de resorte. Puede crear beans de fábrica que son beans regulares, a través de los atributos factory-method/factory-bean en un bean, que elimina la dependencia del resorte de su código.

Usar el segundo enfoque es particularmente útil con la primavera. Puede ordenar a spring que invoque un método después de la inicialización del bean, p. seal() que sella el objeto, lo hace inmutable. Alternativamente, puede implementar un pequeño BeanFactoryPostProcessor para hacer esto automáticamente sin tener que recordar configurar el método init = "sello". en cada frijol inmutable.

+0

Tu respuesta es útil; Seleccioné el otro porque decía "inyección de constructor", lo que cristalizó el problema un poco mejor para mí. – Ladlestein

+0

Quiero usar "final" o, en otro idioma, cualquier mecanismo que signifique y refuerce la inmutabilidad. En Java, ¿Builder realmente me ayuda? ¿No es necesario usar la inyección de constructor para usar el final? – Ladlestein

+0

El constructor puede usar inyección setter, y produce el objeto usando inyección de constructor. c.f. la mayoría de las implementaciones de FactoryBean en Spring: se configuran mediante inyección de setter. – mdma

1

En Java, se puede utilizar un builder para inicializar un objeto inmutable en su constructor, por lo que tendría rehuir definidores.

Si utiliza Scala, sin embargo, la inmutabilidad es the default.

+0

Como dije anteriormente, ¿cómo funciona Builder? Me parece que el Generador no es relevante, a menos que use la inyección de constructor. – Ladlestein

+0

Exactamente, es por eso que dije "tímido lejos de setters". –

0

Para especificar que una clase es inmutable, puede usar la anotación @Immutable.

Puede ver el Javadoc here.

Esto funciona bien con el complemento Findbugs en Eclipse.

@Alexander:

Como lo entiendo, le preguntó cómo especificar que una clase es inmutable. No cómo escribir una clase inmutable. Esta anotación puede brindarle soporte de herramientas para verificar que no tiene un error en su clase que usted alega que es inmutable.

un fragmento del Javadoc:

Necesariamente, esto significa que todos los campos públicos son finales, y que todos los campos de referencia finales públicas se refieren a otros objetos inmutables

+0

-1. Aahh! ¿Hay una anotación '@ NoBugs'? :) –

+1

Punto justo. Vázquez eliminado. –

Cuestiones relacionadas