Rendere una classe pseudo immutabile impostando un flag

1

Ho un progetto java che comporta la costruzione di oggetti piuttosto complessi. Ce ne sono parecchie (dozzine) diverse e alcune hanno un numero enorme di parametri. Devono anche essere immutabili.

Quindi pensavo che il modello di build avrebbe funzionato, ma alla fine ha richiesto molto standard. Un'altra potenziale soluzione che ho pensato è stata quella di creare una classe mutevole, ma dargli una bandiera "congelata", a-la-rubino.

Ecco un semplice esempio:

public class EqualRule extends Rule {
    private boolean frozen;
    private int target;

    public EqualRule() {
        frozen = false;
    }

    public void setTarget(int i) {
        if (frozen) 
            throw new IllegalStateException(
                "Can't change frozen rule.");

        target = i;
    }

    public int getTarget() {
        return target;
    }

    public void freeze() {
        frozen = true;
    }

    @Override
    public boolean checkRule(int i) {
        return (target == i);
    }
}

e "Rule" è solo una classe astratta che ha un metodo "checkRule" astratto.

Questo riduce il numero di oggetti che ho bisogno di scrivere, dandomi anche un oggetto che diventa immutabile a tutti gli effetti. Questo tipo di agisce come se l'oggetto fosse il suo Costruttore ... Ma non proprio.

Tuttavia, non sono troppo eccitato all'idea di avere un immutabile essere camuffato da fagiolo.

Quindi ho avuto due domande: 1. Prima di andare troppo avanti su questa strada, ci sono grossi problemi che qualcuno vede subito? Per quello che vale, è previsto che questo comportamento sia ben documentato ... 2. In caso affermativo, c'è una soluzione migliore?

Grazie

    
posta scott_fakename 25.05.2013 - 18:40
fonte

2 risposte

1

Ecco la proposta di @ 9000 con un setter fluente che restituisce un nuovo oggetto:

public abstract class Rule {

    public Rule shallowClone() {
        // see http://stackoverflow.com/questions/5395501/shallow-vs-deep-copies-in-immutable-objects
    }
}

public class EqualRule extends Rule {

    private int target;

    public int getTarget() {
        return target;
    }

    public EqualRule setTarget(int target) {
         EqualRule clone = super.shallowClone();
         clone.target = target;
         return clone;
    }

    @Override
    public boolean checkRule(int i) {
        return (target == i);
    }
}

boolean result = new EqualRule().setTarget(1).checkRule(1);

Pro: consente la creazione di oggetti immutabili in modo strongmente tipizzato (meno errori umani quando si utilizza il POJO).

Contro: più errori umani durante l'implementazione del POJO.

    
risposta data 26.05.2013 - 10:21
fonte
0

Se non vuoi passare un oggetto mutabile in un oggetto immutabile (o viceversa) puoi usare una mappa.

public class EqualRule extends Rule {

    private final int target;

    public EqualRule(final Map<String,Object> config) {
      this.target = config.get("target");
    }

    public int getTarget() {
        return target;
    }

    @Override
    public boolean checkRule(int i) {
        return (target == i);
    }
}

Puoi automatizzarlo usando la libreria di Jackson. Può iniettare dati su oggetti immutabili (membri finali) o falsi immutabilità (setter privato) automaticamente. Vedi l'annotazione @JsonProperty nella libreria di Jackson :

public class EqualRule extends Rule {

    private final int target;

    @JsonCreator
    public EqualRule(@JsonProperty("target") int target) {
      this.target = target;
    }

    public int getTarget() {
        return target;
    }

    @Override
    public boolean checkRule(int i) {
        return (target == i);
    }
}

final ObjectMapper mapper = new ObjectMapper(); //singleton
final ObjectNode node = mapper.createObjectNode();
node.put("target", 1);
// not as efficient since internally causes serialization/deserialization.
EqualRule rule = mapper.convertValue(node, EqualRule.class);

C'è un vantaggio collaterale che la conversione consente di rendere il codice meno vulnerabile alle modifiche dello schema e più compatibile con le versioni precedenti. Ad esempio quando si converte da json a pojo è possibile gestire o ignorare le proprietà sconosciute.

    
risposta data 25.05.2013 - 22:09
fonte

Leggi altre domande sui tag