Zasady OOP

Opublikowano w grupie Random-PL
Java jest językiem obiektowym. Oznacza to, że musisz pisać programy w Javie w stylu obiektowym. I ten styl opiera się na wykorzystaniu obiektów i klas w programie.

Podstawowe zasady OOP:

Zasady OOP - 1Spróbujmy na przykładach zrozumieć czym są klasy i obiekty oraz jak zastosować w praktyce podstawowe zasady OOP: abstrakcję, dziedziczenie, polimorfizm i enkapsulację.

Co to jest przedmiot?

Świat, w którym żyjemy, składa się z przedmiotów. Jeśli się rozejrzymy, zobaczymy, że otaczają nas domy, drzewa, samochody, meble, naczynia, komputery. Wszystkie te przedmioty są przedmiotami i każdy z nich ma zestaw specyficznych cech, zachowań i przeznaczenia. Jesteśmy przyzwyczajeni do przedmiotów i zawsze używamy ich do bardzo konkretnych celów. Na przykład, jeśli musimy dojechać do pracy, korzystamy z samochodu, jeśli chcemy zjeść, korzystamy z naczyń, a jeśli potrzebujemy odpocząć, potrzebujemy wygodnej sofy. Osoba jest przyzwyczajona do obiektywnego myślenia w celu rozwiązywania problemów w życiu codziennym. Był to jeden z powodów wykorzystywania obiektów w programowaniu i takie podejście do tworzenia programów nazwano obiektowym. Podajmy przykład. Wyobraź sobie, że opracowałeś nowy model telefonu i chcesz uruchomić jego masową produkcję. Jako projektant telefonu wiesz do czego on służy, jak będzie działał i z jakich części będzie się składał (etui, mikrofon, głośnik, przewody, przyciski itp.). Jednak tylko Ty wiesz, jak połączyć te części. Nie planujecie jednak produkować telefonów osobiście, do tego macie całą ekipę pracowników. Aby nie trzeba było za każdym razem tłumaczyć jak połączyć części telefonu i aby wszystkie produkowane telefony wyglądały tak samo, przed rozpoczęciem ich produkcji konieczne będzie wykonanie rysunku w formie opis budowy telefonu. W OOP taki opis, rysunek, diagram czy szablon nazywa się klasą, z której tworzony jest obiekt podczas wykonywania programu. Klasa to opis obiektu, który nie został jeszcze utworzony, czyli ogólny szablon składający się z pól, metod i konstruktora, a obiekt to instancja klasy utworzonej na podstawie tego opisu.

Abstrakcja OOP

Zastanówmy się teraz, jak przenieść się z obiektu w świecie rzeczywistym do obiektu w programie na przykładzie telefonu. Historia tego środka komunikacji przekracza 100 lat, a współczesny telefon, w przeciwieństwie do swojego XIX-wiecznego poprzednika, jest urządzeniem znacznie bardziej skomplikowanym. Używając telefonu, nie myślimy o jego budowie i procesach zachodzących w jego wnętrzu. Po prostu korzystamy z funkcji udostępnionych przez twórców telefonu – przycisków czy ekranu dotykowego do wybierania numeru i wykonywania połączeń. Jednym z pierwszych interfejsów telefonicznych było pokrętło, które obracało się, aby wykonać połączenie. Oczywiście nie było to zbyt wygodne. Mimo to klamka spełniła swoją funkcję prawidłowo. Patrząc na najnowocześniejszy i pierwszy telefon, od razu można rozpoznać najważniejsze szczegóły, istotne zarówno w przypadku urządzenia z końca XIX wieku, jak i ultranowoczesnego smartfona. Oznacza to wykonywanie połączenia (wybieranie numeru) i odbieranie połączenia. Zasadniczo to właśnie sprawia, że ​​telefon jest telefonem, a nie czymś innym. Teraz zastosowaliśmy zasadę w OOP - podkreślanie najważniejszych cech i informacji o obiekcie. Ta zasada OOP nazywa się abstrakcją. Abstrakcję w OOP można również zdefiniować jako sposób reprezentowania elementów rzeczywistego problemu jako obiektów w programie. Abstrakcja zawsze wiąże się z uogólnieniem niektórych informacji o właściwościach obiektów lub obiektów, dlatego najważniejsze jest oddzielenie istotnych informacji od nieistotnych informacji w kontekście rozwiązywanego problemu. W tym przypadku może być kilka poziomów abstrakcji. Spróbujmy zastosować zasadę abstrakcji do naszych telefonów. Najpierw wyróżnijmy najpopularniejsze typy telefonów od samego początku do dnia dzisiejszego. Można je na przykład przedstawić w formie diagramu pokazanego na rysunku 1. Zasady OOP - 2Teraz za pomocą abstrakcji możemy wyróżnić ogólne informacje w tej hierarchii obiektów: powszechny abstrakcyjny typ obiektów - telefon, ogólna charakterystyka telefon - rok powstania i wspólny interfejs - wszystkie telefony mają możliwość odbierania i wysyłania połączeń. Oto jak to wygląda w Javie:
public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outputNumber);
    public abstract void ring (int inputNumber);
}
W oparciu o tę abstrakcyjną klasę będziemy mogli tworzyć w programie nowe typy telefonów, korzystając z innych podstawowych zasad Java OOP, które omówimy poniżej.

Kapsułkowanie

Za pomocą abstrakcji podkreślamy to, co wspólne wszystkim przedmiotom. Każdy model telefonu jest jednak indywidualny i nieco różni się od pozostałych. Jak wyznaczyć granice w programie i wyznaczyć tę indywidualność? Jak możemy mieć pewność, że nikt z użytkowników nie zepsuje nam przypadkowo lub celowo telefonu lub nie będzie próbował przerabiać jednego modelu na inny? W świecie realnych obiektów odpowiedź jest oczywista: wszystkie części trzeba włożyć do obudowy telefonu. Przecież jeśli tego nie zrobimy i pozostawimy całe wnętrze telefonu oraz łączące je przewody na zewnątrz, na pewno znajdzie się dociekliwy eksperymentator, który będzie chciał „poprawić” działanie naszego telefonu. Aby uniknąć takiej ingerencji w projekt i działanie obiektu, OOP wykorzystuje zasadę enkapsulacji - kolejną podstawową zasadę OOP, w której atrybuty i zachowanie obiektu są łączone w jedną klasę, wewnętrzna implementacja obiektu jest ukryta przed użytkownika oraz otwarty interfejs do pracy z obiektem. Zadaniem programisty jest określenie, które atrybuty i metody będą publicznie dostępne, a które są wewnętrznymi implementacjami obiektu i nie powinny być modyfikowane.

Hermetyzacja i kontrola dostępu

Załóżmy, że podczas produkcji na odwrocie telefonu wygrawerowana jest informacja o nim: rok produkcji lub logo firmy producenta. Ta informacja dość specyficznie charakteryzuje ten model - jego stan. Można powiedzieć, że twórca telefonu zadbał o niezmienność tej informacji – mało prawdopodobne, aby komukolwiek przyszło do głowy usunięcie graweru. W świecie Java stan przyszłych obiektów opisywany jest w klasie za pomocą pól, a ich zachowanie za pomocą metod. Możliwość zmiany stanu i zachowania realizowana jest za pomocą modyfikatorów dostępu do pól i metod - private, protected, public, oraz default(dostęp domyślny). Przykładowo uznaliśmy, że rok powstania, nazwa producenta telefonu i jedna z metod należą do wewnętrznej implementacji klasy i nie mogą być zmieniane przez inne obiekty w programie. Używając kodu, klasę można opisać w następujący sposób:
public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    //findComutator
    //openNewConnection...
}
public void call() {
    openConnection();
    System.out.println(„Dzwonię pod numer”);
}

public void ring() {
    System.out.println("Дзынь-дзынь");
}

 }
Modyfikator privatesprawia, że ​​pola i metody klasy są dostępne tylko w obrębie tej klasy. Oznacza to, że privatenie można uzyskać dostępu do pól z zewnątrz ani privatewywołać metod. Ukrycie dostępu do metody openConnectiondaje nam również możliwość swobodnej zmiany wewnętrznej implementacji tej metody, ponieważ gwarantujemy, że metoda ta nie będzie używana przez inne obiekty i nie zakłóci ich działania. Aby pracować z naszym obiektem, pozostawiamy metody otwarte callza pomocą ringmodyfikatora public. Zapewnienie publicznych metod pracy z obiektem jest również częścią mechanizmu enkapsulacji, ponieważ jeśli dostęp do obiektu zostanie całkowicie odrzucony, stanie się on bezużyteczny.

Dziedzictwo

Spójrzmy jeszcze raz na tabelę telefonów. Widać, że reprezentuje on hierarchię, w której model znajdujący się poniżej posiada wszystkie cechy modeli znajdujących się wyżej w gałęzi, plus własną. Przykładowo smartfon do komunikacji wykorzystuje sieć komórkową (ma właściwości telefonu komórkowego), jest bezprzewodowy i przenośny (ma właściwości telefonu bezprzewodowego), może odbierać i wykonywać połączenia (ma właściwości telefonu). W tym przypadku możemy mówić o dziedziczeniu właściwości obiektu. W programowaniu dziedziczenie polega na wykorzystaniu istniejących klas do zdefiniowania nowych. Spójrzmy na przykład tworzenia klasy smartfona za pomocą dziedziczenia. Wszystkie telefony bezprzewodowe zasilane są akumulatorami, których czas pracy jest określony w godzinach. Dodajmy więc tę właściwość do klasy telefonów bezprzewodowych:
public abstract class WirelessPhone extends AbstractPhone {

    private int hour;

    public WirelessPhone(int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
Telefony komórkowe dziedziczą właściwości telefonu bezprzewodowego, do tej klasy dodaliśmy także implementację metod calli ring:
public class CellPhone extends WirelessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println(„Wybieranie numeru” + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println(„Abonent dzwoni do ciebie” + inputNumber);
    }
}
I wreszcie klasa smartfonów, która w odróżnieniu od klasycznych telefonów komórkowych posiada pełnoprawny system operacyjny. Do swojego smartfona możesz dodawać nowe programy obsługiwane przez ten system operacyjny, rozszerzając tym samym jego funkcjonalność. Używając kodu, klasę można opisać w następujący sposób:
public class Smartphone extends CellPhone {

    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program){
    System.out.println(„Instalowanie” + program + "Dla" + operationSystem);
}

}
Jak widać, Smartphonestworzyliśmy bardzo niewiele nowego kodu opisującego klasę, ale otrzymaliśmy nową klasę z nową funkcjonalnością. Stosowanie zasady dziedziczenia OOP może znacząco zmniejszyć ilość kodu, a co za tym idzie ułatwić pracę programiście.

Wielopostaciowość

Jeśli przyjrzymy się wszystkim modelom telefonów, to pomimo różnic w wyglądzie i konstrukcji modeli, możemy zidentyfikować w nich pewne wspólne zachowania – wszystkie potrafią odbierać i wykonywać połączenia oraz mają dość przejrzysty i prosty zestaw przycisków sterujących. Stosując jedną z podstawowych zasad OOP, która jest nam już znana, abstrakcję w ujęciu programistycznym, możemy powiedzieć, że obiekt telefonu ma jeden wspólny interfejs. Dlatego użytkownicy telefonów mogą w miarę wygodnie korzystać z różnych modeli, korzystając z tych samych przycisków sterujących (mechanicznych lub dotykowych), bez wchodzenia w szczegóły techniczne urządzenia. Tak więc stale korzystasz z telefonu komórkowego i możesz łatwo wykonywać połączenia z jego odpowiednika w telefonie stacjonarnym. Zasada obowiązująca w OOP, zgodnie z którą program może używać obiektów z tym samym interfejsem bez informacji o wewnętrznej strukturze obiektu, nazywa się polimorfizmem . Wyobraźmy sobie, że w naszym programie musimy opisać użytkownika, który za pomocą dowolnego modelu telefonu może zadzwonić do innego użytkownika. Oto jak to zrobić:
public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){
// tutaj polimorfizm - użycie abstrakcyjnego typu AbstractPhone phone w kodzie!
        phone.call(number);
    }
}
 }
Opiszmy teraz różne modele telefonów. Jeden z pierwszych modeli telefonów:
public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outputNumber) {
        System.out.println(„Obróć uchwyt”);
        System.out.println(„Daj mi numer telefonu, proszę pana”);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Rozmowy telefoniczne");
    }
}
Zwykły telefon stacjonarny:
public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println(„Dzwonię pod numer” + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Rozmowy telefoniczne");
    }
}
I na koniec fajny telefon wideo:
public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outputNumber) {
        System.out.println(„Łączę kanał wideo dla abonenta” + outputNumber );
    }
    @Override
    public void ring(int inputNumber) {
        System.out.println(„Masz przychodzące połączenie wideo…” + inputNumber);
    }
  }
Utwórzmy obiekty w metodzie main()i przetestujmy metodę callAnotherUser:
AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User(„Andriej”);
user.callAnotherUser(224466,firstPhone);
// Obróć pokrętło
// Podaj mi numer abonenta, proszę pana
user.callAnotherUser(224466,phone);
//Zadzwoń pod numer 224466
user.callAnotherUser(224466,videoPhone);
//Łączę kanał wideo dla abonenta 224466
Wywołując tę ​​samą metodę na obiekcie user, otrzymaliśmy różne wyniki. Wybór konkretnej implementacji metody callw ramach metody callAnotherUserodbywał się dynamicznie w oparciu o konkretny typ obiektu wywołującego podczas wykonywania programu. To jest główna zaleta polimorfizmu – wybór implementacji podczas wykonywania programu. W powyższych przykładach klasy telefonu zastosowaliśmy nadpisywanie metod, czyli technikę zmieniającą implementację metody zdefiniowaną w klasie bazowej bez zmiany sygnatury metody. Zasadniczo jest to zastąpienie metody i to nowa metoda zdefiniowana w podklasie jest wywoływana podczas działania programu. Zwykle podczas zastępowania metody używana jest adnotacja @Override, która informuje kompilator, aby sprawdził podpisy metod przesłanianych i przesłaniających. W rezultacie , aby styl Twojego programu był zgodny z koncepcją OOP i zasadami OOP Java, postępuj zgodnie z poniższymi wskazówkami:
  • podkreślić główne cechy obiektu;
  • podkreślaj wspólne właściwości i zachowania oraz korzystaj z dziedziczenia podczas tworzenia obiektów;
  • używać typów abstrakcyjnych do opisywania obiektów;
  • Staraj się zawsze ukrywać metody i pola związane z wewnętrzną implementacją klasy.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION