Podsumowanie ------------ W części :ref:`Pytonowe1` pojawił się przykład :ref:`process_files-py`, w którym *de facto* wykorzystano wzorzec :ref:`dyspozytor`. W tym przypadku jednak kluczami słownika były napisy, wartościami zaś - funkcje! Czy obiekty rzeczywiście są takie przydatne? W pomiższym przykładzie .. literalinclude:: dyspozytor_func_obj.py :language: python :linenos: wykorzystano obydwa podejścia. Zauważ, że samo wykorzystanie dyspozytora opartego na obiektach (linie 30-31) jest identyczne co w wariancie z funkcjami (linie 12-13). Pisanie klas wydaje się zbędnym wysiłkiem. A jak by można było rozszerzyć funkcjonalność dyspozytora, np. tak, aby zliczał ile razy odezwało się każde ze zwierząt? Dzięki wykorzystaniu obiektów rozwiązanie jest bardzo proste: .. literalinclude:: dyspozytor_func_obj2.py :language: python :linenos: Zauważ, że retriever też szczeka, ale jest liczony oddzielnie niż inne psy! Uważny czytelnik może zauwazy, że problem zliczania, ile razy została wywołana każda z funkcji, można rozwiązać stosując dekoratory funkcji. W takim przypadku jednak trzeba by owe liczniki zapisać jako zmienne globalne. Programowanie obiektowe umożliwia nam schowanie ich we wnętrzu obiektów. Lektura uzupełniająca ~~~~~~~~~~~~~~~~~~~~~ https://rszalski.github.io/magicmethods/ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, *,,Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku''* https://python-3-patterns-idioms-test.readthedocs.io/en/latest/PythonDecorators.html Spis pojęć ~~~~~~~~~~~~~~~~~~~~~ .. glossary:: bazowa klasa klasa po której inna klasa dziedziczy chroniona składowa pole bądź metoda klasy, widoczna tylko dla klas potomnych delegacja wzorzec projektowy destruktor metoda wywoływana automatycznie (i dokładnie raz) w momencie **niszczenia** obiektu; w Pythonie destruktor deklarujemy jako ``__del__()``: .. code-block:: python def __del__(self) : # Zrob coś na samym koncu, np zamknij plik enkapsulacja ukrywanie implementacji; zapewnia ona, że obiekt nie może zmienić nieoczekiwanie stanu innych obiektów. Stan obiektu mogą zmienić jedynie jego metody publiczne, czyli *interfejs*. Enkapsulacja ułatwia testowanie i pielęgnację (*maintenance*) kodu. fabryka klas wzorzec projektowy getter metoda udostępniająca prywatną składową klasy; w Pythonie można ją zadeklarować korzystając z dekoratora ``@property``: .. code-block:: python @property def val(self) : return self.__val # Zwraca prywatną składową ``__val`` interfejs zbiór metod publicznych klasy *iterable* obiekt jest *iterable*, jeżeli umie zwrócić iterator do swojej zawartości; w praktyce jest to `coś`, co można wpisać w pętlę ``for``: .. code-block:: python for l in coś : pass Aby klasa w Pythonie była *iterable*, musi implementować *magiczną* metodę ``__iter__()`` iterator obiekt, który umie zwrócić następny element w sekwencji (posiada metodę ``__next__()``) klasa definicja obiektu; definiuje jego wszystkie pola i metody klasa abstrakcyjna klasa, która posiada choć jedną metodę abstraktyjną; w Pythonie klasy takie muszą dziedziczyć po klasie bazowej ``ABC`` zdefiniowanej w module ``abc`` konstruktor metoda wywoływana automatycznie (i dokładnie raz) w momencie **tworzenia** obiektu; w Pythonie destruktor konstruktor jako ``__init__()``: .. code-block:: python def __init__(self) : # Zainicjuj wszystkie składowe klasy konstruktor domyślny :term:`konstruktor `, który nie przyjmuje żadnych parametrów; ewentualnie korzysta z domyślnych wartości konstruktor kopiujący :term:`konstruktor `, który tworzy głęboką kopię obiektu; nowo utworzony obiekt jest identyczny z tym, który był argumentem konstruktora *magic functions* TBD metoda funkcja zdefiniowana jako składowa klasy metoda abstrakcyjna metoda, która została jedynie zadeklarowana, lecz nie zaimplementowana; metoda taka musi być zaimplementowana w klasie potomnej. W Pythonie metody takie deklarujemy korzystając z dekoratora ``@abstractmethod`` nadklasa dowolna klasa, po której dana klasa dziedziczy (bezpośrednio lub nie) obiekt (instancja klasy) struktura, która może zawierać w sobie funkcje (metody) oraz zmienne (pola) operator wywołania operator zapisywany jako nawiasy zwykłe, czyli ``()``; w Pythonie dodajemy go do klasy implementując w niej *magiczną* metodę ``__call__()`` podklasa synonim do *klasy potomnej* pole (atrybut) klasy zmienna zadeklarowana wewnątrz klasy polimorfizm obiekty tego samego typu (klasy bazowej) zachowują się różnie potomna klasa klasa, która dziedziczy po jakiejś klasie (zwanej *klasą bazową*) prywatna składowa pole bądź metoda klasy, niewidoczna z zewnątrz klasy; jedynie składowe klasy mogą korzystać z prywatnych składowych klasy, do której należą przeciążenie klasa ma kilka metod o takiej samej nazwie lecz różnych argumentach; w Pythonie realizowane przez ``*args`` przesłanianie klasa potomna ma metodę o takiej samej nazwie i argumentach, co klasa bazowa, lecz o zmienionym zachowaniu publiczna składowa pole bądź metoda klasy widoczna dla wszystkich innych obiektów, metod i funkcji; w każdym miejscu kodu można odczytać bądź **zmienić** jej wartość singleton wzorzec projektowy w którym możliwe jest stworzenie tylko jednego obiektu danej klasy statyczne składowe składowe klasy, które nie są związane z żadnym konkretnym obiektem klasy; istnieją nawet wtedy, kiedy jeszcze nie stworzono żadnego obiektu tej klasy; mogą być prywatne lub publiczne