On définit la classe A1
par :
package fr.univ_paris1.mass.poo.cc3.exo1;
public class A1 {
private int u;
private int v;
public A1(int u) {
this.u = u;
v = -1;
}
public void foo() {
u = u + 1;
if (u > 3) {
u = 0;
v = v - 1;
}
}
public void bar() {
u = u - 2;
if (u <= 0) {
u = 3;
v = v + 1;
}
}
@Override
public String toString() {
return v + " [" + u + "]";
}
}
Question : quel est alors l'affichage produit par le code suivant ?
package fr.univ_paris1.mass.poo.cc3.exo1;
public class TestA1 {
public static void main(String[] args) {
A1 x = new A1(2);
System.out.println(x);
for (int i = 0; i < 2; i++) {
x.foo();
}
System.out.println(x);
A1 y = new A1(1);
x.bar();
System.out.println(x + " <-> " + y);
y.bar();
System.out.println(x + " <-> " + y);
}
}
L'affichage obtenu est :
-1 [2] -2 [0] -1 [3] <-> -1 [1] -1 [3] <-> 0 [3]
Question : modifier la classe A1 pour rendre ses instances immuables.
Il faut donc faire en sorte de que les méthodes foo
et bar
ne modifient
plus l'objet appelant mais renvoient au contraire un nouvel objet. Ce principe
conduit à la nouvelle classe suivante :
package fr.univ_paris1.mass.poo.cc3.exo1;
public class A1Immuable {
private int u;
private int v;
public A1Immuable(int u) {
this.u = u;
v = -1;
}
public A1Immuable foo() {
A1Immuable res = new A1Immuable(u + 1);
res.v = v;
if (res.u > 3) {
res.u = 0;
res.v = res.v - 1;
}
return res;
}
public A1Immuable bar() {
A1Immuable res = new A1Immuable(u - 2);
res.v = v;
if (res.u <= 0) {
res.u = 3;
res.v = res.v + 1;
}
return res;
}
@Override
public String toString() {
return v + " [" + u + "]";
}
}
Dans cette solution, on n'utilise pas un nouveau constructeur car on se
contente de modifier directement les variables u
et
v
du nouvel objet res
qui vient d'être créé. On
pourrait bien sûr définir un nouveau constructeur pour ne pas avoir à recopier
explicitement la valeur de this.v
.
Question : Donner les modifications minimales de la méthode main pour obtenir le même affichage avec les objets immuables.
On doit modifier la méthode main
pour récupérer les objets
renvoyés par les nouvelles méthodes. On obtient le code suivant :
package fr.univ_paris1.mass.poo.cc3.exo1;
public class TestA1Immuable {
public static void main(String[] args) {
A1Immuable x = new A1Immuable(2);
System.out.println(x);
for (int i = 0; i < 2; i++) {
x = x.foo();
}
System.out.println(x);
A1Immuable y = new A1Immuable(1);
x = x.bar();
System.out.println(x + " <-> " + y);
y = y.bar();
System.out.println(x + " <-> " + y);
}
}
On définit la classe B1
par :
package fr.univ_paris1.mass.poo.cc3.exo2;
import java.math.BigInteger;
public class B1 {
private BigInteger a;
public B1() {
a = BigInteger.ZERO;
}
public B1 f(int x) {
if (x >= 0 && x <= 9) {
B1 r = new B1();
BigInteger tmp = a.multiply(BigInteger.TEN);
r.a = tmp.add(BigInteger.valueOf(x));
return r;
} else {
return this;
}
}
public B1 g() {
B1 r = new B1();
r.a = a.divide(BigInteger.TEN);
return r;
}
@Override
public String toString() {
return a.toString();
}
}
Question : quel est alors l'affichage produit par le code suivant ?
package fr.univ_paris1.mass.poo.cc3.exo2;
public class TestB1 {
public static void main(String[] args) {
B1 b = new B1();
System.out.println(b);
b.f(5);
System.out.println(b);
B1 c = b.f(5);
System.out.println(b + " " + c);
B1 d = c;
c = c.f(8);
System.out.println(c + " " + d);
d = d.f(4).f(7);
System.out.println(c + " " + d);
B1 e = new B1();
e = e.f(5);
e = e.f(10);
System.out.println(e);
System.out.println(e.g() + " " + e);
}
}
L'affichage obtenu est :
0 0 0 5 58 5 58 547 5 0 5
Question : Modifier la classe B1 pour rendre ses instances modifiables en conservant un comportement comparable.
Il suffit cette fois ci de modifier les méthodes f
et
g
en leur permettant de changer le contenu de a
. Ce principe
conduit à la nouvelle classe suivante :
package fr.univ_paris1.mass.poo.cc3.exo2;
import java.math.BigInteger;
public class B1Modifiable {
private BigInteger a;
public B1Modifiable() {
a = BigInteger.ZERO;
}
public void f(int x) {
if (x >= 0 && x <= 9) {
BigInteger tmp = a.multiply(BigInteger.TEN);
a = tmp.add(BigInteger.valueOf(x));
}
}
public void g() {
a = a.divide(BigInteger.TEN);
}
@Override
public String toString() {
return a.toString();
}
}
On définit la classe C1
par :
package fr.univ_paris1.mass.poo.cc3.exo3;
public class C1 {
private String bli;
public C1(String bli) {
this.bli = bli;
}
public void foo() {
bli = "";
}
public String bar(String u) {
String r = bli;
bli = u;
return r;
}
}
Question : Donner un exemple de programme simple qui montre que les instances de C1 sont modifiables.
Il suffit de construire un programme montrant que le comportement d'une
instance de C1
change après l'appel d'une méthode. Ici, la
méthode bar
renvoie le contenu de la variable bli
avant l'appel, tout en modifiant sa valeur. Il suffit donc d'appeler deux fois
de suite la méthode pour constater une modification du résultat, comme dans le
programme suivant :
package fr.univ_paris1.mass.poo.cc3.exo3;
public class TestC1 {
public static void main(String[] args) {
C1 x = new C1("Toto");
System.out.println(x.bar("Titi"));
System.out.println(x.bar("Titi"));
}
}
qui affiche :
Toto Titi
On définit la classe D1
par :
package fr.univ_paris1.mass.poo.cc3.exo4;
public class D1 {
private double z;
public D1(double z) {
this.z = z;
}
public void inc() {
z = z + 2.0;
}
}
Question : Expliquer brièvement pourquoi les objets de la classe D1 sont immuables.
On constate qu'aucune méthode ne permet de déterminer le contenu de l'objet
(c'est-à-dire celui de la variable z
). De ce fait, rien ne permet de constater un
éventuel changement de comportement après un appel de méthode, ce qui rend
l'objet immuable du point de vue de l'utilisateur.
Question : Ajouter une méthode (simple) rendant modifiables les objets de la classe D1.
Il suffit d'ajouter une méthode permettant d'accéder au contenu de la
variable z
, comme par exemple :
public double getZ() {
return z;
}
On définit la classe E1
par :
package fr.univ_paris1.mass.poo.cc3.exo5;
import java.util.Arrays;
public class E1 {
private char[] x;
public E1() {
x = new char[0];
}
public int plop(String s) {
if (s.length() > 0) {
if (x.length == 4) {
x = new char[] { s.charAt(0) };
return 1;
} else {
char[] r = new char[x.length + 1];
for (int i = 0; i < x.length; i++) {
r[i] = x[i];
}
r[x.length] = s.charAt(0);
x = r;
return r.length;
}
} else {
return -1;
}
}
@Override
public String toString() {
return Arrays.toString(x);
}
}
Question : quel est alors l'affichage produit par le code suivant ?
package fr.univ_paris1.mass.poo.cc3.exo5;
public class TestE1 {
public static void main(String[] args) {
E1 u = new E1();
u.plop("Toto");
System.out.println(u);
System.out.println(u.plop("Ututu"));
System.out.println(u.plop("Lock"));
System.out.println(u);
u.plop("plop");
System.out.println(u.plop(""));
u.plop("clop");
System.out.println(u);
}
}
L'affichage obtenu est :
[T] 2 3 [T, U, L] -1 [c]