Avem o problemă simplă: un număr poate varia între o valoare minimă și una maximă; utilizatorul poate decide care sunt aceste limite. Cum facem?
În principiu vom avea o clasă care va păstra aceste limite și vor exista metode care să permite modificarea lor. Mai putem decide și că există niște valori implicite. Le putem alege noi și/sau putem crea un constructor care primește cele două valori. Prima implementare consideră că valorile implicite sunt 5 și 10. Vom modifica minimul la 2 și maximul la 5 și vom afișa intervalul.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class MinMax1 { private int min = 5, max = 10; public void setMin(int min) { this.min = min; } public void setMax(int max) { this.max = max; } public static void main(String[] args) { MinMax1 minMax = new MinMax1(); minMax.setMin(2); minMax.setMax(5); System.out.println("Interval: [" + minMax.min + ", " + minMax.max + "]"); } } |
Pare simplu, dar sunt câteva probleme. Să începem cu una simplă: ce se întâmplă dacă modificăm doar minimul, dar acesta devine mai mare decât maximul? De exemplu, am putea elimina linia 15 și modifica linia 14 în:
1 |
minMax.setMin(20); |
Nu e prea bine fiindcă nu ar mai exista nicio valoare posibilă pentru numărul nostru (intervalul ar deveni [20, 10]). Așadar, nu ar trebui să permitem acest lucru.
Pentru ca cei care folosesc clasa noastră să știe dacă modificarea a fost permisă sau nu, am putea modifica metodele astfel încât să returneze o valoare booleană care indică dacă operația s-a efectuat sau nu cu succes. Noua implementare ar fi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class MinMax2 { private int min = 5, max = 10; public boolean setMin(int min) { if (min > max) return false; this.min = min; return true; } public boolean setMax(int max) { if (max < min) return false; this.max = max; return true; } public static void main(String[] args) { MinMax2 minMax = new MinMax2(); minMax.setMin(20); minMax.setMax(50); System.out.println("Interval: [" + minMax.min + ", " + minMax.max + "]"); } } |
Observăm că modificarea din linia 18 nu este efectuată, dar intervalul final este valid.
Problema este că un utilizator obișnuit nu se așteaptă la acest efect. Dacă dorește să modifice limitele, nu se așteaptă ca una dintre modificări să eșueze datorită unui detaliu intern de implementare.
Evident, pot fi inversate liniile 18 și 19 și atunci totul va funcționa corect, dar utilizatorul trebuie să aibă informații suplimentare legate de implementare, ceea ce nu e chiar bine.
Am putea crede că e OK să modificăm tot timpul prima data maximul și apoi minimul, dar nu e așa. De exemplu, dacă intervalul inițial ar fi [5, 10] și am dori să devină [2, 4], trebuie modificată prima dată valoarea minimă. Din nou, utilizatorul trebuie să fie atent.
S-ar putea spune că totuși nu e foarte complicat și utilizatorul trebuie doar să fie atent la ordinea în care efectuează operațiile. Pentru acest exemplu, e destul de simplu - să-l complicăm puțin...
De data aceasta vom lucra cu două intervale. Să presupunem că într-un grup pot exista un număr de fete cuprins între două limite și un număr de băieți cuprins între două alte limite. Avem două intervale acum, fiecare cu problema anterioară. Implementarea ar fi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public class MinMax3 { private int minFete = 5, maxFete = 10, minBaieti = 5, maxBaieti = 10; public boolean setMinFete(int minFete) { if (minFete > maxFete) return false; this.minFete = minFete; return true; } public boolean setMaxFete(int maxFete) { if (maxFete < minFete) return false; this.maxFete = maxFete; return true; } public boolean setMinBaieti(int minBaieti) { if (minBaieti > maxBaieti) return false; this.minBaieti = minBaieti; return true; } public boolean setMaxBaieti(int maxBaieti) { if (maxBaieti < minBaieti) return false; this.maxBaieti = maxBaieti; return true; } public static void main(String[] args) { MinMax3 minMax = new MinMax3(); minMax.setMaxFete(50); minMax.setMinFete(20); minMax.setMaxBaieti(50); minMax.setMinBaieti(20); System.out.println("Fete: [" + minMax.minFete + ", " + minMax.maxFete + "]"); System.out.println("Baieti: [" + minMax.minBaieti + ", " + minMax.maxBaieti + "]"); } } |
Dar... pentru a simplifica situația, am putea decide că limitele inferioare pot fi modificate deodată (la fel și cele superioare). Vom permite modificarea doar dacă ambele valori noi sunt acceptabile. Să vedem o implementare:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class MinMax4 { private int minFete = 5, maxFete = 10, minBaieti = 5, maxBaieti = 10; public boolean setMin(int fete, int baieti) { if (fete > maxFete || baieti > maxBaieti) return false; this.minFete = fete; this.minBaieti = baieti; return true; } public boolean setMax(int fete, int baieti) { if (fete < minFete || baieti < minBaieti) return false; this.maxFete = fete; this.maxBaieti = baieti; return true; } public static void main(String[] args) { MinMax4 minMax = new MinMax4(); minMax.setMax(50, 50); minMax.setMin(20, 20); System.out.println("Fete: [" + minMax.minFete + ", " + minMax.maxFete + "]"); System.out.println("Baieti: [" + minMax.minBaieti + ", " + minMax.maxBaieti + "]"); } } |
Dar... acum devine interesant; dacă am dori ca noul interval pentru fete să fie [20, 50], iar cel pentru băieți să fie [2, 4]? Apelurile ar fi:
1 2 |
minMax.setMin(20, 2); minMax.setMax(50, 4); |
În orice ordine le-am pune, nu s-ar întâmpla nimic. Pentru una dintre valori modificarea ar crea un interval invalid, deci nu ar fi efectuată. Deci... așa ceva nu se face! Mai exact, nu ar trebui să se facă, dar o astfel de decizie de proiectare este uneori luată, de exemplu aici și aici.
Cu puțină imaginație am putea ajunge la intervalele pe care ni le dorim, dar nu ar trebui să fim nevoiți să facem astfel de artificii. O variantă ar fi:
1 2 3 4 |
minMax.setMax(50, 10); minMax.setMin(20, 10); minMax.setMin(20, 2); minMax.setMax(50, 4); |
Dar, dacă am trece la trei intervale? Sau un șir de intervale? Numărul artificiilor crește exponențial. Am greșit dacă am ales o astfel de abordare.
Soluția este simplă. Trebuie să ni se permite să modificăm minimum și maximul deodată. Iar dacă avem mai multe intervale și vrem să modificăm mai multe intervale deodată, trebuie să putem preciza minimele și maximele deodată. Pentru un singur interval nu trebuie să verificăm decât faptul că noul interval este valid și nu ne mai interesează care a fost cel vechi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class MinMax5 { private int min = 5, max = 10; public boolean setMinMax(int min, int max) { if (min > max) return false; this.min = min; this.max = max; return true; } public static void main(String[] args) { MinMax5 minMax = new MinMax5(); minMax.setMinMax(20, 50); System.out.println("Interval: [" + minMax.min + ", " + minMax.max + "]"); } } |
Implementarea pentru grupul de fete și băieți este similară.
Ar putea părea natural că așa ar fi trebuit să facem și probabil așa am fi făcut dacă ne-am fi gândit puțin. Din nefericire, uneori alegem soluții "exotice" fiindcă nu ne dăm seama care sunt consecințele lor. Cu alte cuvinte, cam sărim a doua fază dintre cele trei prezentate în acest articol.