Cześć! Poświęćmy dzisiejszy wykład enkapsulacji i zacznijmy go od razu przykładami :) Zasady enkapsulacji - 1Przed tobą znajoma maszyna do napojów gazowanych . Mam do Ciebie jedno pytanie: jak to działa? Spróbuj odpowiedzieć szczegółowo: skąd wypada szklanka, jak utrzymuje się temperatura wewnątrz, gdzie przechowywany jest lód, jak maszyna rozumie, który syrop dodać itp. Najprawdopodobniej nie znasz odpowiedzi na te pytania. Cóż, może nie wszyscy korzystają z takich maszyn, w chwili obecnej nie są one tak popularne. Spróbujmy podać inny przykład. Coś, czego na pewno używasz wiele razy każdego dnia. O, jest pomysł! Zasady enkapsulacji - 2 Wyjaśnij, jak działa wyszukiwarka Google. Jak dokładnie szuka informacji o wprowadzonych przez Ciebie słowach? Dlaczego te wyniki są na górze, a nie inne? Chociaż codziennie korzystasz z Google, prawdopodobnie o tym nie wiesz. Ale to nie jest ważne. W końcu nie musisz tego wiedzieć. Możesz wprowadzać zapytania do wyszukiwarki bez zastanawiania się, jak to działa. Możesz kupić napój gazowany z automatu, nie wiedząc, jak to działa. Można prowadzić samochód nie rozumiejąc, jak działa silnik spalinowy i nie znając w ogóle fizyki, nawet na poziomie szkolnym. Wszystko to jest możliwe dzięki jednej z głównych zasad programowania obiektowego – enkapsulacji . Czytając różne artykuły na ten temat, na pewno zetknąłeś się z faktem, że w programowaniu istnieją dwa wspólne pojęcia – enkapsulacja iukrycie . A pod słowem „enkapsulacja” autorzy mają na myśli jedno, a potem drugie (tak się po prostu złożyło). Przeanalizujemy oba terminy, abyś miał pełne zrozumienie. Pierwotne znaczenie słowa „ enkapsulacja ” w programowaniu to połączenie danych i metod pracy z tymi danymi w jednym pakiecie („kapsułce”). W Javie enkapsulacja to . Klasa zawiera zarówno dane (pola klasy), jak i metody pracy z tymi danymi. Zasady enkapsulacji - 3 Wydaje ci się to oczywiste, ale w innych koncepcjach programistycznych wszystko układa się inaczej. Na przykład w programowaniu funkcyjnym dane są ściśle oddzielone od operacji na nich wykonywanych. W OOP (programowanie obiektowe) programy składają się z klas kapsułek, które są zarówno danymi, jak i funkcjami do pracy z nimi. Porozmawiajmy teraz o ukrywaniu się . Jak to jest, że używamy wszelkiego rodzaju skomplikowanych mechanizmów, nie rozumiejąc, jak one działają i na czym polegają? To proste: ich twórcy zapewnili prosty i przyjazny dla użytkownika interfejs. W automacie z napojami interfejsem są przyciski na panelu. Naciskając jeden przycisk, wybierasz objętość szklanki. Naciskając drugi, wybierasz syrop. Trzeci odpowiada za dodawanie lodu. I to wszystko, co musisz zrobić. Nie ma znaczenia, jak maszyna jest ułożona w środku. Najważniejsze jest to, że jest zaprojektowany tak, że użytkownik musi nacisnąć trzy przyciski, aby uzyskać napój gazowany . To samo z samochodem. Nieważne, co się w nim dzieje. Najważniejsze jest to, że po naciśnięciu prawego pedału samochód jedzie do przodu, a po naciśnięciu lewego pedału zwalnia . Na tym polega istota ukrywania. Wszystkie „wnętrza” programu są ukryte przed użytkownikiem. Dla niego ta informacja jest zbędna, niepotrzebna. Użytkownikowi potrzebny jest efekt końcowy, a nie wewnętrzny proces. Spójrzmy na klasę jako przykład Auto:

public class Auto {

   public void go() {

       /* Some complicated things happen inside the car.
       As a result, it moves forward */
   }

   public void brake() {

       /* Some complicated things happen inside the car.
       As a result, it slows down. */
   }

   public static void main(String[] args) {

       Auto auto = new Auto();

       // From the user's perspective,

       // one pedal is pressed and the car accelerates.
       auto.gas();
      
       // The other is pressed, and the car slows down.
       auto.brake();
   }
}
Tak wygląda ukrywanie implementacji w programie Java. Wszystko jest jak w prawdziwym życiu: użytkownik otrzymuje interfejs (metody). Jeśli potrzebuje samochodu w programie do wykonania akcji, wystarczy wywołać żądaną metodę. A to, co dzieje się w tych metodach, to zbędne informacje, najważniejsze jest to, że wszystko działa tak, jak powinno. Tutaj rozmawialiśmy o ukrywaniu implementacji . Oprócz tego Java ma również ukrywanie danych . Pisaliśmy o tym w wykładzie o getterach i setterach , ale nie będzie zbyteczne przypominanie. Na przykład mamy klasę Cat:

public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

  
}
Może pamiętacie z ostatniego wykładu jaki jest problem z tymi zajęciami? Jeśli nie, pamiętajmy. Problem polega na tym, że jego dane (pola) są otwarte dla wszystkich, a inny programista może łatwo stworzyć w programie bezimiennego kota o wadze 0 i wieku -1000 lat:

public static void main(String[] args) {

   Cat cat = new Cat();
   cat.name = "";
   cat.age = -1000;
   cat.weight = 0;

}
W takiej sytuacji możesz bacznie obserwować, czy któryś z Twoich kolegów nie tworzy obiektów ze złym stanem, ale znacznie lepiej byłoby wykluczyć samą możliwość tworzenia takich „niewłaściwych obiektów”. Zasady enkapsulacji - 4 W ukrywaniu danych pomagają nam:
  1. modyfikatory dostępu ( private , protected , package default );
  2. pobierające i ustawiające.
Możemy na przykład postawić tam czek, aby zobaczyć, czy ktoś nie próbuje przypisać kotu liczby ujemnej jako wiek. Jak powiedzieliśmy wcześniej, autorzy różnych artykułów na temat enkapsulacji mają na myśli albo enkapsulację (łączenie danych i metod), albo ukrywanie, albo jedno i drugie. Oba mechanizmy są obecne w Javie (niekoniecznie tak jest w innych językach OOP), więc ta druga opcja będzie najbardziej poprawna. Stosowanie enkapsulacji daje nam kilka ważnych korzyści:
  1. Kontrola nad prawidłowym stanem obiektu. Przykłady tego były powyżej: dzięki seterowi i modyfikatorowi private zabezpieczyliśmy nasz program przed kotami o wadze 0.

  2. Przyjazność dla użytkownika dzięki interfejsowi. Pozostawiamy „na zewnątrz” tylko dla metod dostępu użytkownika. Wystarczy, że do nich zadzwoni, by uzyskać wynik, a w szczegóły ich pracy wcale nie musi się zagłębiać.

  3. Zmiany w kodzie nie mają wpływu na użytkowników. Wszystkie zmiany przeprowadzamy wewnątrz metod. Nie wpłynie to na użytkownika: tak jak napisał auto.gas() dla gazu samochodu, napisze to w ten sam sposób. A fakt, że zmieniliśmy coś w działaniu metody gazowej (), pozostanie dla niego niewidoczny: on, jak poprzednio, po prostu otrzyma pożądany rezultat.