Zapouzdření Tomáš Pitner, Radek Ošlejšek, Marek Šabo 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é slovo private • Chceme, aby mohl konstruktor a třídu používat skutečně každý? ⇒ použijeme klíčové slovo public 1 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 jako private ◦ 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 a private.  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řídu Person všude Person p = new Person("Marek", 23); // even from another class/package • Klíčové slovo private zabraňuje získat hodnotu atributů p.name, p.age. 2 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;   } } 3 Viditelnost atributů • Není lepší udělat atribut public, namísto vytváření metod get a set? • 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 metodu set: ◦ 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 za age? • 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 4 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? 5 • metoda transferTo přistupuje přímo k balance • 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); } 6