Abstrakcja w OOP: Ukrywanie złożoności
Prowadzisz samochód, wykonując kilka prostych czynności. Naciskasz pedał gazu. Skręcasz kierownicą. Naciskasz hamulec.
Nie musisz wiedzieć, jak paliwo trafia do silnika. Nie musisz rozumieć, jak poruszają się tłoki ani jak zmieniają się biegi. Samochód ukrywa przed Tobą te szczegóły. Używasz prostego interfejsu, aby kontrolować złożoną maszynę.
Oprogramowanie działa w ten sam sposób.
Pomyśl o wysyłaniu e-maila. Wywołujesz jedną komendę: emailService.send().
Za kulisami dzieje się wiele rzeczy:
- System waliduje adres.
- Tworzy połączenie SMTP.
- Autoryzuje się u dostawcy.
- Buduje wiadomość.
- Obsługuje ponowne próby, jeśli pierwsza próba się nie powiedzie.
Nie musisz widzieć tych kroków. Interesuje Cię tylko to, że e-mail zostaje wysłany.
Gdybyś nie użył abstrakcji, Twój kod wyglądałby tak:
- connect()
- authenticate()
- buildMessage()
- sendMessage()
- disconnect()
Robienie tego za każdym razem tworzy problemy. Każda część Twojego kodu wie zbyt wiele. Jeśli zmienisz dostawcę poczty, będziesz musiał zaktualizować każdą linię kodu, która wysyła wiadomości. Twój system staje się trudny do zmiany.
Abstrakcja rozwiązuje ten problem. Pokazuje, co obiekt robi, ale ukrywa, jak to robi.
Udostępniasz prosty interfejs. Wywołujący pozostaje skoncentrowany na zadaniu. Implementacja pozostaje ukryta. Dzięki temu Twój kod jest luźno powiązany i łatwy w utrzymaniu.
Ludzie często mylą abstrakcję z enkapsulacją.
Enkapsulacja pyta: Kto może zmieniać te dane? Chroni stan wewnętrzny. Abstrakcja pyta: Jakich szczegółów użytkownik potrzebuje? Ukrywa złożoność.
Współpracują ze sobą, aby budować lepsze systemy.
Następnie przyjrzymy się dziedziczeniu. Odpowiemy na jedno pytanie: Jeśli obiekty mają wspólną funkcjonalność, czy musisz pisać ten sam kod dwa razy?