Los objetos inmutables son aquellos que no pueden cambiar su estado una vez creados.
public class User {
private final String passport;
private final String name;
private final String lastName;
private final String email;
private final String school;
public UserManual(final String passport, final String name,
final String lastName, final String email,
final String school) {
this.passport = passport;
this.name = name;
this.lastName = lastName;
this.email = email;
this.school = school;
}
También se puede conseguir con los record de Java:
public record UserRecord(String passport, String name,
String lastName, String email,
String school) {
}
En principio, haciendo los atributos private final y ofreciendo métodos de acceso, estos objetos permanecerán inmutables. Aunque tenemos que tener en cuenta que si pasamos otro objeto, ese sí que podría no ser inmutable.
public record Immutable(List<String> list) {
}
//Alteramos el estado interno
final Immutable actual = new Immutable(new ArrayList<>());
actual.list().add("1");
Y al igual que con una lista podemos hacer lo mismo con otros objetos que no sean inmutables. Una solución es que la gestionemos nosotros, o hacer una copia defensiva y convertirla en una lista no modificable.
No obstante, a veces sí es necesario que parte sea modificable o que pueda tener ciertas operaciones. Aunque lo mejor es que todo sea inmutable, porque te ayuda a entender mejor el código, ya que sabes que los objetos que ves no cambian de estado por el camino.
Por ejemplo, una llamada a una función podría alterar el estado de un objeto y no ser visible en la función principal. Además, los objetos inmutables son thread-safe por esa misma razón.
Que los objetos sean inmutables nos hace pensar de otra manera, y es que programar con objetos inmutables es una programación funcional, donde para poder tener un nuevo estado acabamos creando un nuevo objeto.
Mientras que en la programación imperativa se cambia el estado de los objetos.
Para hacer objetos inmutables, necesitas que no puedan heredarse, porque al heredar se podría sobrescribir su comportamiento.
Hay dos estrategias para hacer eso, una es haciendo la clase final y la otra con constructor privado y factoría estática (lo explico con más detalle en el patrón Singleton).
Los objetos inmutables deberían cumplir las siguientes propiedades:
- No tener métodos que permitan modificar propiedades
- No permitir que la clase pueda heredarse
- Que todas las propiedades sean final
- Que todas las propiedades sean private
- En caso de tener propiedades que sean objetos, no deberíamos confiar en el cliente y hacer copias defensivas.
Referencias
Joshua Bloch, Effective Java (3ª edición), Addison-Wesley, 2018.
Top comments (0)