Co je zapouzdření
-
Naprosto zásadní vlastnost objektového přístupu, možná nejzásadnější
-
Jde o spojení dat a práce s nimi do jednoho celku - objektu
-
Data jsou v atributech objektu, práce je umožněna díky metodám objektu
-
Data by měla být zvenčí (jinými objekty) přístupná jen prostřednictvím metod
-
Data jsou tedy "skryta" uvnitř, zapoudřena
-
To zajistí větší bezpečnost a robustnost, přístup k datům máme pod kontrolou
Motivace zapouzdření
class Person {
String name;
int age;
Person(String inputName, int inputAge) {
name = inputName;
age = inputAge;
}
}
Co když:
-
Nechceme, aby kdokoli mohl modifikovat atributy
name
,age
po vytvoření objektu -
Většinou ale chceme, aby konstruktor a třídu mohl používat každý
Řešení — práva přístupu
-
Nastavíme viditelnost nebo též práva přístupu pomocí modifikátorů třídy, metody nebo atributu
-
Nechceme modifikovat atributy
name
,age
po vytvoření objektu? ⇒ použijeme klíčové slovoprivate
-
Chceme, aby mohl konstruktor a třídu používat skutečně každý? ⇒ použijeme klíčové slovo
public
public class Person {
private String name;
private int age;
public Person(String inputName, int inputAge) {
name = inputName;
age = inputAge;
}
}
4 typy viditelnosti v zkratce
-
public
= veřejný, může používat každý i mimo balík ⇒ používejte na třídy a (některé) metody -
private
= soukromý, nemůže používat nikdo mimo třídy ⇒ používejte na atributy -
protected
= chráněný ⇒ používá se při dědičnosti, vysvětlíme později -
modifikátor neuveden, pak jde o možnost přístupu "package local"
-
v rámci balíku se chová jako
public
, mimo něj jakoprivate
-
v našem kurzu tento typ nebudeme používat
-
-
Ujistěte se, že vždy máte zadefinovaný práva přístupu/typ viditelnosti.
-
V drtivé většině budete používat
public
aprivate
.
Každá veřejná třída musí být v souburu se stejným jménem. |
Metody get
& set
— motivace
public class Person {
private String name;
private int age;
public Person(String inputName, int inputAge) {
name = inputName;
age = inputAge;
}
}
-
Klíčové slovo
public
umožňuje použít tříduPerson
všudePerson p = new Person("Marek", 23); // even from another class/package
-
Klíčové slovo
private
zabraňuje získat hodnotu atributůp.name
,p.age
.
Metody get
-
Chci získat hodnotu atributu i po vytvoření objektu,
-
ale zabránit jeho modifikaci?
-
Do třídy přidáme metodu, která bude veřejná a po zavolaní vrátí hodnotu atributu.
public int getAge() {
return age;
}
-
Takové metody se slangově nazývají "gettery".
-
Mají návratovou hodnotu podle typu vraceného atributu.
-
Název metody je vždy
get
+ jméno atributu s velkým písmenem (getAge
,getName
, …).
Metody set
-
Chci-li nastavit hodnotu atributu i po vytvoření objektu:
public void setAge(int updatedAge) {
age = updatedAge;
}
-
Metoda je veřejná a po jejím zavolaní přenastaví původní hodnotu atributu.
-
Takové metody se slangově nazývají settery.
-
Mají návratovou hodnotu typu
void
(nevrací nic). -
Název metody je vždy
set
+ jméno atributu s velkým písmenem (setAge
,setName
, …).
Příklad atribut a get
& set
public class Person {
private String name; // attribute
public String getName() { // its getter
return name;
}
public void setName(String newName) { // its setter
name = newName;
}
}
Viditelnost atributů
-
Není lepší udělat atribut
public
, namísto vytváření metodget
aset
?
-
Není, neumíme pak řešit tyhle problémy:
-
Co když chci jenom získat hodnotu atributu, ale zakázat modifikaci (mimo třídy)? ⇒ Řešení: odstraním metodu
set
-
Chci nastavit atribut věk (v třídě
Person
) pouze na kladné číslo? ⇒ Řešení: upravím metoduset
:-
if (updatedAge > 0) age = updatedAge;
-
-
Chci přidat kód provedený při získávání/nastavování hodnoty atributů? ⇒ Řešení: upravím metodu
get
/set
-
Gettery & settery se dají ve vývojových prostředích (NetBeans, IDEA) generovat automaticky.
Využití this
public void setAge(int updatedAge) {
age = updatedAge;
}
-
Mohli bychom nahradit jméno parametru
updatedAge
zaage
? -
Ano, ale jak bychom se potom dostali k atributu objektu?
-
Použitím klíčového slova
this
:
public void setAge(int age) {
this.age = age;
}
-
this
určuje, že jde o atribut objektu, nikoli parametr (lokální proměnnou)
Korektní použití třídy I
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void writeInfo() {
System.out.println("Person " + name);
}
public String getName() {
return this.name;
}
}
Korektní použití třídy II
-
Vytvoříme dvě instance (konkrétní objekty) typu
Person
.
public class Demo {
public static void main(String[] args) {
Person ales = new Person("Ales");
Person beata = new Person("Beata");
ales.writeInfo();
beata.writeInfo();
String alesName = ales.getName(); // getter is used
// String alesName = ales.name; // forbidden
}
}
Třída Account
— připomenutí
public class Account {
private double balance;
public void add(double amount) {
balance += amount;
}
public void writeBalance() {
System.out.println(balance);
}
public void transferTo(Account whereTo, double amount) {
balance -= amount; // change the balance
whereTo.add(amount);
}
}
-
Co je zde malý nedostatek?
-
metoda
transferTo
přistupuje přímo kbalance
-
ale přístup k
balance
by měl být nějak lépe kontrolován (např. zda z účtu neberu více, než smím)!
Třída Account
— řešení
-
řešení: znovupoužijeme metodu
add
, která se o kontrolu zůstatku postará -
(i když to třeba ještě teď neumí!)
public void transferTo(Account whereTo, double amount) { this.add(-amount); whereTo.add(amount); }