2017-02-20 7 views
3

Lorsque nous créons des classes immuables à l'aide de la bibliothèque Immutable objects, comment pouvons-nous gérer les membres mutables (par exemple j.u.Date)?articles mutables à Immuable

REMARQUE: cela est pas sur la classe Date de java et totalement en rapport avec les objets Immuable bibliothèque java qui va générer un code!

Exemple:

@Value.Immutable 
public interface MyImmutableClass { 
    Date creationDateTime(); 
} 

Est-il possible de passer outre le getter, de sorte qu'elle retourne une copie?

public Date creationDateTime() { 
    return new Date(creationDateTime.getTime()); 
} 
+2

Vous pouvez utiliser une [classe de date immuable] (https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html), ou, oui, par tous les moyens avoir votre getter renvoie une copie. 'return new Date (créationDateTime.getTime()); ' – khelwood

+0

Je ne peux pas utiliser les fonctionnalités de java8 et cela peut aussi affecter d'autres classes - pas seulement la date. – TmTron

+0

Voir aussi http://stackoverflow.com/questions/7082553/java-util-date-clone-or-copy-to-not-expose-internal-reference – khelwood

Répondre

1

de ma question dans le Immutables issue tracker j'ai appris que la façon la plus propre de manipuler des objets mutables est d'utiliser un custom encoding annotation.

J'ai créé un petit projet open source tmtron-immutables encoding pour créer une telle annotation pour la classe java.util.Date. Cela devrait être un bon point de départ pour quiconque veut créer un encodage personnalisé.

Ensuite, vous pouvez directement utiliser votre classe mutable (par exemple java.util.Date) comme attribut et toujours obtenir la même immuabilité garantie que pour les attributs immuables (comme String, long, etc.)

@Value.Immutable 
@DateEncodingEnabled 
public interface ValueObject { 
    Date creationDate(); 
} 

L'annotation @DateEncodingEnabled fera Assurez-vous que seule la valeur longue immuable de l'objet Date est stockée dans la classe ImmutableValueObject.

1

Est-il possible de passer outre le getter, de sorte qu'elle retourne une copie?

Un peu comme vous l'avez écrit là:

public Date creationDateTime() { 
    return new Date(creationDateTime.getTime()); 
} 

(comme khelwood a souligné dans les commentaires ci-dessus).

Cependant, si vous voulez éviter une mutation accidentelle de creationDateTime dans votre classe, pensez simplement stocker les Millis comme final long:

private final creationDateTimeMillis; 

public Date creationDateTime() { 
    return new Date(creationDateTimeMillis); 
} 

Alors que vous pouvez appeler Date.setTime() même si le Date est final, muter ainsi la état interne, vous ne pouvez pas réaffecter creationDateTimeMillis.

+0

Eh bien, je sais que je dois le copier en quelque sorte: La question est "Comment dire au processeur d'annotation Immutables de le faire?" – TmTron

1

Vous pouvez faire la méthode générée protected et servir le champ uniquement à partir d'une méthode de lecture de clonage:

@Value.Immutable 
public abstract class WrapMutable { 
    protected abstract Date timestamp(); 

    public Date getTimestamp() { 
     return new Date(timestamp().getTime()); 
    } 
} 

Toute utilisation du champ est alors par sa copie-getter, alors que la méthode timestamp() sert uniquement à définir le compositeur dans le constructeur:

WrapMutable obj = ImmutableWrapMutable.builder().timestamp(new Date()).build(); 
System.out.println(obj.getTimestamp()); 
System.out.println(obj.timestamp()); // Error: timestamp() has protected access in WrapMutable 
+0

Ce n'est pas vraiment immuable. Créez simplement une sous-classe de 'WrapMutable', et vous pouvez ajouter une méthode pour appeler' timestamp() 'de manière néfaste. Vous devez avoir la propriété 'timestamp' stocker/retourner quelque chose immuable, comme un' long'. –

+0

@AndyTurner: Vous avez lu la question dans le contexte de [Immutables framework] (http://immutables.github.io/). Son but n'est pas de se prémunir contre les développeurs malveillants, ce qui peut être très utile lors des tests, mais plutôt de fournir des instances POJO sur lesquelles vous pouvez faire des tonnes d'hypothèses, par ex. que les collections sont initialisées, que les champs sont définis, que les optionnels ne sont pas nuls, etc. Si vous travaillez avec le framework, cela élimine beaucoup de messages standard et vous aide à réduire le nombre de codages défensifs requis. – Henrik