Programowanie obiektowe – oczami Kowalskiego

Czym jest programowanie obiektowe?

Pozwól, że posłużę się słowami Steva Jobsa, który w 1994 roku dla magazynu Rolling Stone dał taką wypowiedź o programowaniu obiektowym:

Objects are like people. They’re living, breathing things that have knowledge inside them about how to do things and have memory inside them so they can remember things. And rather than interacting with them at a very low level, you interact with them at a very high level of abstraction, like we’re doing right here.

Here’s an example: If I’m your laundry object, you can give me your dirty clothes and send me a message that says, “Can you get my clothes laundered, please.” I happen to know where the best laundry place in San Francisco is. And I speak English, and I have dollars in my pockets. So I go out and hail a taxicab and tell the driver to take me to this place in San Francisco. I go get your clothes laundered, I jump back in the cab, I get back here. I give you your clean clothes and say, “Here are your clean clothes.”

You have no idea how I did that. You have no knowledge of the laundry place. Maybe you speak French, and you can’t even hail a taxi. You can’t pay for one, you don’t have dollars in your pocket. Yet I knew how to do all of that. And you didn’t have to know any of it. All that complexity was hidden inside of me, and we were able to interact at a very high level of abstraction. That’s what objects are. They encapsulate complexity, and the interfaces to that complexity are high level.

Pokuszę się o przetłumaczenie jego wypowiedzi:

Obiekty są jak ludzie. Są żyjącymi, oddychającymi istotami, które wiedzą jak wykonywać pewne rzeczy i mają pamięć, by mogły rzeczy pamiętać. I zamiast oddziaływać na siebie na bardzo niskim poziomie – oddziałują na bardzo wysokim poziomie abstrakcji. Tak jak my w codziennym życiu.

Tutaj podam przykład: Jeśli ja jestem obiektem Pralnia, możesz dać mi brudne ciuchy i wysłać mi wiadomość “Czy możesz wyprać mi moje ubrania, proszę.” Tak się składa, że wiem gdzie są najlepsze pralnie w San Francisco. Mówię po angielsku i mam dolary w kieszeni. Więc wychodzę i łapię taksówkę. Proszę taksówkarza, by zawiózł mnie do wskazanej pralni. Piorę Twoje ciuchy, wracam do taxi i przyjeżdżam z powrotem do Ciebie. Oddaję Ci rzeczy i mówię “Tutaj są Twoje czyste ubrania.”

Nie masz pojęcia co zrobiłem, by je wyprać. Nie masz wiedzy o pralniach w San Francisco. Być może mówisz tylko po francusku i nawet nie potrafisz złapać taksówki. Nie możesz też zapłacić, bo nie masz dolarów. Jednak ja jestem zdolny do tych wszystkich rzeczy. A Ty nie musiałeś wiedzieć, jak się robi którąkolwiek z nich. Cała ta złożoność była ukryta we mnie, a my mogliśmy oddziaływać na siebie na bardzo wysokim poziomie abstrakcji. To są właśnie obiekty. One ukrywają swoją złożoność, prezentując jedynie interfejs na wysokim poziomie.

Jest to nieco potoczne wyjaśnienie, jednak oddaje sedno sprawy.

Oczywiście, Pralnia to robocza nazwa człowieka, który odbiera od nas pranie i zawozi do prawdziwej pralni, po czym oddaje nam wyprane rzeczy.

W programowaniu obiektowym chodzi o to, by zamykać część funkcjonalności w postaci obiektów. Obiekt wystawia na zewnątrz metody, dzięki którym może się porozumiewać z innymi obiektami.

Tak przykładowo, obiekt Pralnia pokazuje innym obiektom, że może zrobić pranie i nic więcej. Nie pokazuje, że odda je do pralni, że pojedzie taksówką i że będzie płacić. Ta funkcjonalność jest zamknięta wewnątrz tego obiektu.

Obiekty posiadają również własne cechy. Przykładowo dla obiektu Pralnia, mogą to być wiek, płeć, stan portfela. Generalnie, właściwości obiektów nie powinno się dać zmieniać z zewnątrz.

Zobacz, jak bardzo takie podejście upraszcza i systematyzuje programowanie.

Mając gotowy obiekt Pralnia, jako programista, nie musisz się martwić krokami, które należy wykonać, by wyprać ubrania. Po prostu wywołujesz jedną metodę i masz pranie zrobione.

Możesz skupić się na całości programu jako szerszej perspektywy. Projektujesz interakcje miedzy obiektami, zamiast skupiać się na detalach.

Jak tworzy się obiekty?

Wspaniale, gdy nasz obiekt Pralnia jest już gotowy i możemy z niego korzystać.

Zanim jednak to nastąpi, musimy nauczyć nasz program, w jaki sposób obiekt Pralnia ma być utworzony i jak ma wykonywać swoje czynności.

Obiekty tworzymy za pomocą klasy.

To klasa jest swoistą definicją obiektu. Opisuje, jakie ma parametry i metody, co będzie widoczne na zewnątrz, a co jest funkcjonalnością ukrytą. W jaki sposób obiekt się tworzy i co się dzieje, gdy się niszczy.

Tworząc nowy obiekt, wskazujemy, jakiej ma być klasy.

Możemy stworzyć wiele obiektów będących tej samej klasy.

Co może definiować klasa?

Klasa zawiera w sobie wszystkie informacje związane z obiektami jej typu.

Są to:

  • własności obiektu (zmienne)
  • metody (funkcje, które wykonuje obiekt)
  • dziedziczenie (czy obiekt będzie wzorował się na obiekcie nadrzędnym)
  • implementacja interfejsu (czy musi zawierać pewne metody)
  • metody magiczne (konstruktory, destruktor i inne – zobacz w dokumentacji)

Własności obiektu

To nic innego jak zmienne, które są zawarte wewnątrz stworzonego obiektu.

Tak, wracając do naszego przykładu z gościem od pralni. Jego własności to przykładowo: wiek, płeć, stan portfela, ilość ubrań i tym podobne.

Są to cechy, które opisują dany obiekt.

Metody

To zbiór funkcji zdefiniowanych dla tego obiektu.

W opisanym przykładzie mogłyby być takie: zrób pranie, zamów taksówkę, pobierz opłatę, szukaj klienta itp.

Są to czynności, które obiekt może wykonać.

Dziedziczenie i implementacja interfejsu

W programowaniu zorientowanym obiektowo istnieje możliwość tworzenia pewnych obiektów bazując na innym obiekcie (dziedziczenie) lub gotowym schemacie (interfejsy).

W przypadku dziedziczenia wskazujemy klasę, która ma zostać rozszerzona.

Oznacza to, że klasa dziedzicząca będzie miała dokładnie te same metody co dziedziczona, plus można ją rozszerzyć o dodatkową funkcjonalność.

W naszym przykładzie może to wyglądać następująco:

Pojawia się nowy obiekt – Pralnia Ekspresowa. Nowa pralnia ma dokładnie te same własności i może wykonywać te same czynności co tradycyjna Pralnia. Plus, pojawia się nowa metoda – zrób pranie w 15 minut.

Wtedy, by uniknąć kopiowania kodu i przepisywania tych samych metod i własności, nowa klasa dziedziczy po klasie bazowej i otrzymuje dokładnie te same metody i własności. My jedynie wzbogacamy ją o nowe możliwości.

W przypadku interfejsu tworzymy schemat, do którego musi dopasować się klasa, która go implementuje.

Interfejs np. może wymusić posiadanie metody o danej nazwie.

W naszym przykładzie może to wyglądać następująco:

Tworzymy interfejs ICzyszczenieUbran, który wymusza na klasie posiadania metody zrobPranie. Teraz tworząc jakąkolwiek nową klasę, która będzie mogła wyprać ubrania, implementujemy w niej ten interfejs.

Klasa Pralnia, implementując ten interfejs, posiada metodę zrobPranie.

Teraz może pojawić się klasa Pralniomat, implementująca interfejs ICzyszczenieUbran, która również będzie musiała posiadać metodę zrobPranie.

To jak z McDonald’sem – nieważne czy w Polsce, czy w Stanach czy Południowych Chinach – każdy zaserwuje Ci BigMac’a.

Metody magiczne

To stwierdzenie akurat znajduje swoje zastosowanie stricte w PHP i językach pochodnych.

W Javie czy C# go nie spotkasz.

Metody magiczne to nowość wprowadzona w PHP5. Wykonują się automatycznie a ich nazwy zaczynają się od podwójnego podkreślenia __’.

Wspominam o nich teraz wyłącznie w ramach ciekawostki. Jeśli chcesz dowiedzieć się więcej, zobacz:

http://www.php.rk.edu.pl/w/p/metody-magiczne/

http://wortal.php.pl/Wortal/Artykuly/PHP/Podstawy/Programowanie-obiektowe-dla-poczatkujacych/Metody-magiczne

Opowiem o nich więcej, gdy przejdziemy do pisania własnego kodu.

Modyfikatory dostępu

Przydatną funkcjonalnością, bez której programowanie obiektowe nie mogłoby się obejść, jest modyfikacja dostępu do zawartości klasy (i jej obiektów).

Tym sposobem, w PHP wyróżniamy zasoby:

  • publicznie dostępne (modyfikator public)
  • dostępne wyłącznie wewnątrz klasy i klasach dziedziczących (modyfikator protected)
  • dostępne wyłącznie wewnątrz klasy (modyfikator private)

Wracając do przykładu Pralni, metoda zrobPranie będzie metodą publiczną, gdyż inne obiekty mogą z niej skorzystać.

Natomiast takie pola jak wiek czy płeć będą prywatne, gdyż nie chcemy, by ktoś mógł je zmieniać.

Metodą protected byłoby np. łapanie taksówki, co mogą robić jedynie obiekty typu Pralnia lub pralniopochodne (jak wspomniana wcześniej Pralnia Ekspresowa).

Podsumowując

Programowanie obiektowe ma przyczynić się do zwiększenia czytelności kodu i ułatwić zarządzanie nim.

Porządnie i przejrzyście ustrukturyzowany kod jest tańszy w utrzymaniu i szybszy w rozbudowie. Programowanie jest łatwiejsze, gdy nie musisz się długo zastanawiać, gdzie masz wprowadzić poprawkę.

Oczywiście, znajdą się tacy, którzy piszą wszystko w oparciu na funkcjach i ich kod też działa.

To nie jest tak, że pisząc obiektowo jesteś w stanie napisać bardziej zaawansowane rzeczy niż bez wykorzystania obiektów.

Po prostu to, co dobrze napiszesz obiektowo, będzie dużo bardziej czytelne i znacznie łatwiej będzie dokładać kolejne funkcjonalności.

8 Responses on this post

  1. I do dziś dnia … nie poprawił 😛
    ” …. z powrotem do Ciebie” …. wizałem pewne nadzieje 😛
    fajnie.

  2. Panie Marcinie, dziękuję za świetne materiały o OOP.
    Mam pytanie, dlaczego możliwa jest zmiana prywatnej właściwości $car1 poprzez metodę obiektu $car2. Jakoś nie daje mi to spokoju 🙂
    Dzięki, pozdrawiam

    class Car {
    private $type;
    private $model;
    private $engine;

    public function __construct($type, $model, $engine) {
    $this->type = $type;
    $this->model = $model;
    $this->engine = $engine;
    }
    public function aconstruct($car) {
    $this->type = $car->type;
    $car->type = ‘Why Can I put it here and change another object?’;
    $this->model = $car->model;
    $this->engine = $car->engine;
    }
    public function getCarType() {
    return $this->type;
    }
    }
    $car = new Car(“Opel”, “Insignia”, “diesel”);
    $car2 = new Car(“Ford”, “Fiesta”, “benzin”);
    $car2->aconstruct($car);
    echo $car2->getCarType() . “\n”;
    echo $car->getCarType();
    $car->type = ‘this is not possible of course!’;
    echo $car->getCarType();

    1. Hej Tomku,

      dziękuję za pozytywną opinię 🙂 co do podesłanego kodu – wygląda to na bug w samym języku. Wątpię, by ktoś świadomie i celowo zostawił taką lukę. W założeniach nie powinno być takiej możliwości. Aż muszę to sobie sprawdzić, czy faktycznie tak zadziała.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *