Je suis actuellement en train de mettre en œuvre des solveurs itératifs, qui fonctionnent en améliorant successivement l'estimation de la solution à un problème spécifique. Comme la solution est un ensemble de données plutôt important, le raffinement est effectué en place.Encapsulation d'un objet mutable dans un objet en lecture seule
J'ai implémenté un simple pattern Observer/Observable afin de pouvoir observer l'algorithme pendant les itérations. En particulier, le solveur fournit une méthode
Foo getCurrentSolution()
qui renvoie l'estimation actuelle de la solution. L'observateur est alors libre de faire quelques calculs, basés sur l'estimation actuelle (par exemple: décider si la solution est assez bonne et si les itérations peuvent être arrêtées). Foo
est mutable, mais bien sûr, si l'observateur modifie l'estimation actuelle de la solution, cela peut ruiner les itérations du solveur.
Par conséquent, getCurrentSolution()
devrait vraiment retourner une copie défensive. Mais cela nécessite du temps et de la mémoire sur les gros problèmes, donc je suis venu avec une autre idée, qui est getCurrentSolution()
retourner un nouveau ReadOnlyFoo(bar)
, où foo
est l'estimation actuelle (mutable) de la solution, privée au solveur. L'idée est que ReadOnlyFoo
a presque la même interface que Foo
, seules les méthodes qui pourraient modifier les données sont "désactivées" (elles lèvent une exception). Tous les détails de certaines classes factices sont donnés ci-dessous.
Ma question est la suivante: cette approche est-elle une bonne pratique? Y a-t-il un meilleur modèle?
Merci! Sébastien
public abstract class AbstractFoo{
public abstract double getValue();
public abstract void setValue(final double x);
public abstract AbstractFoo add(AbstractFoo bar);
public void addToSelf(AbstractFoo bar){
setValue(getValue + bar.getValue());
}
}
public class Foo extends AbstractFoo{
private double value;
public Foo(final double x){
value = x;
}
public double getValue(){
return value;
}
public void setValue(final double x){
value = x;
}
public AbstractFoo add(AbstractFoo bar){
return new Foo(value + bar.getValue());
}
}
public final class FooReadOnly extends AbstractFoo{
private final Foo foo;
public FooReadOnly(AbstractFoo foo){
this.foo = foo;
}
public double getValue(){
return foo.getValue();
}
public void setValue(final double x){
throw new NotImplementedException("read only object");
}
public AbstractFoo add(AbstractFoo bar){
return foo.add(bar);
}
public void addToSelf(AbstractFoo bar){
throw new NotImplementedException("read only object");
}
}
Ce serait certainement plus propre, mais supposez que je ne peux pas changer l'implémentation de 'Solution'? Je ne peux pas le faire hériter de 'MutableSolution' ... – Sebastien
Puis définissez une interface, avec les méthodes en lecture seule seulement, qui est retournée par getCurrentSolution, et définissez une classe implémentant cette interface et déléguant à votre objet mutable. –
Je ne suis pas satisfait de l'autre option, donc je pense que je vais aller pour celui-ci. Merci beaucoup. – Sebastien