Недеља 3 — Класе, објекти и енкапсулација
Код: GitHub · преузми пројекат (ZIP) · задатак за самостални рад
Ове недеље први пут прелазимо са програма који првенствено обрађује податке на програм у коме објекти чувају стање и нуде операције над тим стањем.
Главни пример је једноставан дигитални новчаник. Новац представљамо целим бројем динара (int) да се не бисмо бавили проблемима заокруживања реалних бројева — тема примера је објектно-оријентисани дизајн, не финансијски софтвер.
Циљеви
После вежби студент треба да уме да објасни:
- разлику између класе и објекта;
- шта представља стање објекта;
- зашто јавна поља омогућавају да објекат заврши у неисправном стању;
- зашто
privateпоља + аутоматски getteri/setteri нису сама по себи добра енкапсулација; - шта је инваријанта објекта;
- зашто је често боље понудити операцију (
uplati,plati) него setter (setStanje); - чему служе конструктор и
this; - разлику између чланова објекта и
staticчланова класе; - основну употребу
finalпоља; - да променљива класног типа садржи референцу на објекат;
- да Java аргументе увек прослеђује по вредности — код објеката се копира вредност референце;
- чему служе пакети и који нивои видљивости постоје (
private, без модификатора,public).
Редослед примера
primer01_javna_polja
Намерно лош почетни модел. Показује да корисник класе може директно да постави немогуће стање, нпр. негативан износ новца.
primer02_setter_nije_enkapsulacija
Поља постају private, али уводимо setStanje. Проблем практично остаје исти. Пример служи да раздвојимо појмове сакривање података и енкапсулација.
primer03_invarijante
Објекат више нема setStanje. Стање се мења кроз смислене операције uplati и plati. Класа сама чува своју инваријанту: стање новчаника никада није негативно.
primer04_konstruktori_static_final
Модел добија идентитет. Сваки новчаник има јединствени ID који се додељује помоћу заједничког static бројача. ID и власник су final, док је стање променљиво.
primer05_reference
Две променљиве могу показивати на исти објекат. Пример такође демонстрира да промена самог објекта из методе остаје видљива позиваоцу, али превезивање локалног параметра на други објекат не мења променљиву позиваоца.
primer06_paketi
Покренути primer06_paketi.Main. package даје пуно име типу, а import скраћује
писање имена. Подпакет није исти пакет: a и a.b имају одвојене границе приступа.
private члан види његова класа (уз правила приступа угњеждених типова), члан без
модификатора види исти пакет, а public је јавни API. protected детаљније радимо
уз наслеђивање. final референца не гарантује да је објекат на који показује непроменљив.
Централна порука
private није циљ сам по себи.
Добра класа треба да одреди које операције имају смисла над њеним стањем и да спречи да објекат заврши у стању које нема смисла у домену проблема.
Уместо:
novcanik.setStanje(-5000);
желимо API који говори језиком проблема:
novcanik.uplati(2000);
novcanik.plati(750);
Питања за дискусију
- Да ли класа са свим
privateпољима аутоматски има добру енкапсулацију? - Зашто
setStanjeније добра операција за дигитални новчаник? - Ко треба да провери да ли на новчанику има довољно средстава — позивалац или сам
Novcanik? - Да ли сваки податак мора да има getter?
- Да ли сваки податак мора да има setter?
- Шта би се десило када би
stanjeбилоfinal? - Зашто
sledeciIdтреба да будеstatic, аidне треба? - Ако две променљиве показују на исти објекат, колико објеката постоји?
- Када проследимо
Novcanikметоди, да ли Java прослеђује објекат „по референци“?
Мали задатак
На крају директоријума налази се ZADATAK.md. Задатак користи исти скуп идеја, али други домен, како би студент морао сам да препозна инваријанте и смислен API класе.
Границе операција
Провера iznos > Integer.MAX_VALUE - stanje спречава прекорачење пре сабирања.
Одбијање операције не сме делимично да промени објекат.