• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Abstrakcja - wyjaśnienie

Object Storage Arubacloud
0 głosów
1,821 wizyt
pytanie zadane 27 sierpnia 2018 w Java przez periedynek Obywatel (1,320 p.)

Cześć. Ucze się podstaw OOP Javy.

Jestem na etapie interfejsów i klas abstrakcyjnych.

Znalazłem takie info:

Abstraction is a process of hiding the implementation details and showing only functionality to the user.

Abstraction lets you focus on what the object does instead of how it does it.

There are two ways to achieve abstraction in java

  1. Abstract class (0 to 100%)
  2. Interface (100%)

I tutaj mam pytanie. W jaki sposób chowamy implementajcę danej metody, bo tego nie rozumiem. 

Najlepiej jakiś przykład.

4 odpowiedzi

+7 głosów
odpowiedź 28 sierpnia 2018 przez RafalS VIP (122,820 p.)
wybrane 28 sierpnia 2018 przez periedynek
 
Najlepsza

Z abstrakcją masz do czynienia na co dzień. Weźmy taką skrzynie biegów w aucie. Skrzynia biegów jest tutaj interfejsem, to co dzieję się pod spodem gdy zmieniasz bieg Cię nie interesuje. Są to szczegóły implementacyjne. Interfejs to ruszanie lewarka. Specjalistą nie jestem, ale załóżmy, że w bebechach skrzyni biegów mogą być wykorzystane różne technologie. Ciebie to jednak nie interesuje, bo Ty musisz jedynie znać interfejs skrzyni biegów, żeby z niej korzystać. Jak wsiądziesz do innego auta, w którym mechanizm zmiany biegów jest rozwiązany jakoś inaczej to Ciebie to nie interesuje, bo Tobie wystarczy jednie wiedza o tym jak z tej skrzyni korzystać. Implementacja jest schowana.

Inny przykład - pilot do telewizora. Obchodzi Cię, w jaki sposób on przesyła wiadomości do telewizora? Nie. Bo jest to szczegół implementacyjny. Różne piloty przesyłają wiadomości w różny sposób, ale mają ten samy interfejs:

interface Pilot {
    void wlaczTV();
}

class PilotBluetooth implements Pilot{

    @Override
    public void wlaczTV() {
        //logika specyficzna dla wlaczenia telewizora po blutucie
    }
}

class PilotPodczerwien implements Pilot{

    @Override
    public void wlaczTV() {
        //logika specyficzna dla wlaczenia telewizora po podczerwieni
    }
}

Dzięki takiej abstrakcji możesz poruszać się w skomplikowanym systemie bez poznawania każdej klasy. Możesz operować na abstrakcjach (interfejsach). Możesz korzystać z różnych pilotów nie wiedzać wcale jaka magia dzieje się pod spodem, żeby pilot włączyl telewizor.

To był przykład na zrozumienie. Teraz przykład bardziej programistyczny:

class Customer {}

interface CustomerStorage{
    void add(Customer c) throws IOException;
    void remove(Customer c) throws IOException;
}

class CustomerFileStorage implements CustomerStorage{
    //file handling logic
}

class CustomerSQLDatabaseStorage implements CustomerStorage{
    //sql database logic
}

W ten sposób za pomocą abstrakcji uzyskujemy identyczną sytuacje jak ze skrzynią biegów czy pilotem. Programiste, który korzysta z klas implementujących CustomerStorage nie obchodzą bebechy klasy tylko jej interfejs. Liczy się, że dana implementacja będzie umożliwiać zapisywanie i usuwanie Customerów z "przechowalni danych". Jak to zrobi? Nieistotne. Szczegóły implementacyjne zostały "ukryte".

Jak w kodzie używa się ukrytych implementacji? Zmienna typu interfejsu może przechowywać różne implementacje tego interfejsu:

CustomerStorage storage = new CustomerSQLDatabaseStorage();
storage = new CustomerFileStorage();

Więc można napisać klasę korzystającą z jakiegoś rodzaju przechowalni customerów, która nawet nie wie z której klasy będzie korzystać:

class Library{
    CustomerStorage storage;
    Library(CustomerStorage storage){
        this.storage = storage;
    }
    void registerCustomer(Customer c){
        storage.add(c);
    }
}
komentarz 28 sierpnia 2018 przez periedynek Obywatel (1,320 p.)
edycja 28 sierpnia 2018 przez periedynek

O coś takiego właśnie mi chodziło. 

Nie rozumiem jednej rzeczy:


CustomerStorage storage = new CustomerSQLDatabaseStorage();
storage = new CustomerFileStorage();

Co jeżeli zrobiłbym

CustomerSQLDatabaseStorage storage = new CustomerSQLDatabaseStorage();

Tutaj też ta klasa implementuje interfejs. Tutaj już nie ma abstrakcji, tak?

Btw. W Twoim przykładzie mamy doczynienia z polimorfizmem?

komentarz 28 sierpnia 2018 przez RafalS VIP (122,820 p.)

Tak to, że wywołanie metody na zmiennej typu interfejsu wywoła metodę z faktycznej implementacji, którą w tym momencie zmienna przechowuje to polimorfizm.

CustomerSQLDatabaseStorage storage = new CustomerSQLDatabaseStorage();

Tutaj nie korzystamy z tego, że klasa implementuje interfejs. Z interfejsami chodzi troche o generyczność. Jeśli zmienna jest typu interfejsu to może być tam wstawiona dowolna implementacja tego interfejsu. W Twoim przypadku zmienna storage może przechowywać tylko obiekty klasy CustomerSQLDatabaseStorage i jej pochodne. Jeśli zrobisz funkcję z parametrem typu CustomerSQLDatabaseStorage to tracisz uniwersalność. Mówisz, że tutaj może być tylko obiekt CustomerSQLDatabaseStorage i jego rozszerzenia.

Nie przejmowałbym się na początek aż tak pojęciami takimi jak abstrakcja. Naucz się z niej korzystać w praktyce :P

komentarz 28 sierpnia 2018 przez periedynek Obywatel (1,320 p.)

Własnie chce się tymi przejmować, z tego względu że chce sobie ugruntować jakoś wiedze. Zawsze do tego podchodziłem na luzie w wyniku czego za 2 tygodnie nie wiedziałem co to w ogóle jest. 

Tutaj nie korzystamy z tego, że klasa implementuje interfejs.

`class CustomerSQLDatabaseStorage implements CustomerStorage...`

Jak z tego nie korzystamy? Wymuszamy na CustomerSQLDatabaseStorage jakieś zachowania, które zostały zapisane w CustomerStorage.

. Jeśli zrobisz funkcję z parametrem typu CustomerSQLDatabaseStorage to tracisz uniwersalność. Mówisz, że tutaj może być tylko obiekt CustomerSQLDatabaseStorage i jego rozszerzenia.

W takim razie 

`CustomerSQLDatabaseStorage storage = new CustomerSQLDatabaseStorage();`

jest gorszym rozwiązaniem od `CustomerStorage storage = ....` ?

komentarz 28 sierpnia 2018 przez RafalS VIP (122,820 p.)
Fakt. Wymuszenie implementacji wciąż dziala, ale tylko w momencie pisania klasy. Pozniej gdy operujemy na zmiennych typu klas a nie interfejsow juz z tego nie korzystamy.

Ogolnie rzecz biorąc - tak. Lepiej jest operowac na interfejsach niz klasach. Zyskujesz w ten sposob uniwersalność, co najczesciej jest pozadane. Mozesz podmienic obiekt na inny implementujacy ten sam interfejs, a implementacja interfejsu wymusi implementacje przez klasy wymaganych metod.
komentarz 28 sierpnia 2018 przez periedynek Obywatel (1,320 p.)
Na ten moment chyba rozumiem. Dziękuję.
komentarz 28 sierpnia 2018 przez must Bywalec (2,980 p.)

Widzę, że wykorzystałeś przykład z bazy danych, którą implementowaliśmy:D

W takim razie tutaj: https://github.com/must1/CarRental/blob/master/src/main/java/car/rental/Main.java

 w 10 linijce powinienem zrobić tak jak tutaj @periedynek pisałeś:

CustomerStorage storage = new CustomerSQLDatabaseStorage();

Mógłbyś napisać coś więcej o plusach tego?

komentarz 28 sierpnia 2018 przez RafalS VIP (122,820 p.)

W 10 linijce nie ma to żadnego znaczenia, bo zaraz po stworzeniu wstrzykujesz zmienną do innej klasy, która trzyma już ją przy pomocy interfejsu.

Sytuacje, w których użycie

ArrayList<Integer> list = new ArrayList<>();

zamiast

List<Integer> list = new ArrayList<>();

byłoby sensowne to rzadko spotykane wyjątki (o ile takie istnieją, teraz nic sobie nie przypominam), więc dobrą praktyką jest używanie interfejsów gdzie tylko się da. Nic na tym nie stracisz, a w wielu przypadkach sporo zyskasz.

Oczywiście dobrze by było, żebyś robił to świadomie i czuł kiedy i co zyskujesz, ale tak jak napisałem wcześniej - na pewno nic nie tracisz.

komentarz 28 sierpnia 2018 przez mbabane Szeryf (79,280 p.)

@RafalS, Super to wyjaśniłeś. I analogie, żeby lepiej zrozumieć i przykłady z kodem - superos!

+2 głosów
odpowiedź 28 sierpnia 2018 przez adas94 Nałogowiec (29,200 p.)
Zauważyłem, że pod każdą odpowiedzią dopytujesz o koncepcję polimorfizmu i jej sensu.

Być może ten wpis pozwoli Ci na lepsze zrozumienie tej koncepcji i ułożenia sobie wiedzy w głowie.

http://javastyle.pl/java/polimorfizm-z-wykorzystaniem-interfejsow/
+1 głos
odpowiedź 27 sierpnia 2018 przez marcin99b Szeryf (82,180 p.)
Chodzi o to, że interfejs ma tylko to, co musi mieć

Podam to na przykładzie c#
Mamy kolekcje (listy)
Jest kolekcja List - która przechowuje praktycznie wszystkie operacje dotyczące list
I ona implementuje kilka interfejsów
Między innymi IEnumerable, który służy tylko do odczytu

Tym sposobem chcąc wystawić coś z informacją "jestem tylko do odczytu", wystawiasz IEnumerable
Jeśli chcesz wystawić liste z opcją edycji, wystawiasz List

Chodzi o to, że różne interfejsy mogą mieć różne odpowiedzialności
W tym przypadku jest to na zasadzie interfejsu "tylko do odczytu", gdzie programista dostający obiekt pod tym interfejsem ma dostęp tylko do tych opcji, które pokazuje interfejs, czyli sam odczyt
komentarz 27 sierpnia 2018 przez periedynek Obywatel (1,320 p.)
Ale ja wywołuje metodę z klasy którą implementuje ten interfejs, a nie metodę z interfejsu prawda?
komentarz 27 sierpnia 2018 przez marcin99b Szeryf (82,180 p.)

Nie wiem jak w javie 
Ale w c# wyglądałoby tak 

Interfejs obj = new Klasa();

//teraz wykonując operacje na obj, masz dostęp tylko do tych metod klasy "Klasa", które posiada interfejs 

//Np klasa Dog() ma jakieś szczekanie
//A interfejs IAnimal tylko to, co umie każde zwierze, czyli np jedzenie, bieganie itd
//I używając 

IAnimal animal = new Dog()

//nie będziesz miał opcji szczekania, a jedynie jakieś jedzenie, picie, bieganie
//ma to taki plus, że możesz tu podstawić też klasę Cat() która też implementuje IAnimal
//i nie wiedząc co jakim zwierzęciem sterujesz, możesz rozkazać mu np biegnąć 

 

komentarz 27 sierpnia 2018 przez periedynek Obywatel (1,320 p.)
Teraz już sie zamotałem na maksa.

Zawsze używałem interfejsu, po prostu ze go implementowałem.

I tworzyłem instację tej klasy która implementowała interfejs. Tam już nie ma abstrakcji?
komentarz 27 sierpnia 2018 przez periedynek Obywatel (1,320 p.)
Po co jest wszystko w ogole.
komentarz 28 sierpnia 2018 przez marcin99b Szeryf (82,180 p.)
chodzi o to, że możesz mieć specyficzne interfejsy
do konkretnych czynności

taka pojedyncza odpowiedzialność

tworząc interfejs tworzysz go po coś, często żeby móc podstawić sobie pod niego inną klase, która go implementuje
albo właśnie, żeby ograniczyć ilość metod widocznych na zewnątrz
możesz to zrobić hermetyzacją (publiczne/prywatne), albo właśnie wypisywaniem w interfejsie tylko tego, co ma być "publiczne"
komentarz 28 sierpnia 2018 przez marcin99b Szeryf (82,180 p.)
w mini projektach to nie ma sensu

ale w projekcie tworzonym wiele dni/tygodni/miesięcy
a szczególnie takim, nad którym pracuje wiele osób
trudno bez tego przetrwać (bo każdy będzie się gubił)

to po prostu ułatwienia dla programistów, żeby przekazywać informacje "co miałem na myśli"

do tego interfejsy pozwalają na prostsze testowanie pewnych aktywności i podmianę klas, ale to akurat inny temat
komentarz 28 sierpnia 2018 przez marcin99b Szeryf (82,180 p.)
np przekazujesz obiekt o którym z góry wiadomo "to ma być tylko do odczytu"
i mimo że klasa ma 20 metod, ty przekazujesz tylko te 5, które odpowiadają za sam odczyt
przez co reszta zespołu i ty w przyszłości wiecie, że to było projektowane z myślą, żeby było "tylko do odczytu"
+1 głos
odpowiedź 28 sierpnia 2018 przez miro Pasjonat (23,870 p.)

W jaki sposób chowamy implementajcę danej metody, bo tego nie rozumiem. 

Będę dawać przykłady dotyczące interfejsów z javy7, aby nie komplikować. W interfejsach znajdują się metody abstrakcyjne bez żadnej implementacji. Dopiero klasa implementuj ten interfejs jest zmuszona dostarczyć implementację oraz może mieć swoje dodatkowe metody, pola. 
Można powiedzieć, że interfejs to API mówiący co można zrobić. Natomiast jak to to zrobić, pokazują klasy implementujące. Przez to wyodrębniasz jakąś abstrakcję z większej całości oraz możesz podmieniać algorytm stojący za jakąś funkcjonalnością. 
Wydaje mi się, że dobrze to obrazuje wzorzec strategii. https://sourcemaking.com/design_patterns/strategy 

komentarz 28 sierpnia 2018 przez periedynek Obywatel (1,320 p.)

Dopiero klasa implementuj ten interfejs jest zmuszona dostarczyć implementację oraz może mieć swoje dodatkowe metody, pola.  

Do tego momentu wszystko rozumiem. Ale no własnie klasa implementująca teninterfejs musi dostarczyć implementację. A korzystając poźniej ja używam tejże klasy, tworzę jej instacje, prawda? Coś na zasadzie

interface Example
{
public void run();
}

public class ClassImplementingInterface implements Example
{
@Overriden
void run(){
              System.out.println("Run");
}

}

i w Mainie później 

`ClassImplementingInterface classImplementingInterface = new ClassImplemenetingInterface();`

I tutaj przecież implementacja jest wystawiona. Tutaj tak jakby interfejsu nie używam. Interfejs użyłem tutaj tylko w taki sposób aby wymusić jakieś czynności na klasie jej implementujacęj.

Podobne pytania

+2 głosów
1 odpowiedź 217 wizyt
pytanie zadane 12 marca 2023 w C# przez piter11251 Obywatel (1,280 p.)
0 głosów
1 odpowiedź 149 wizyt
pytanie zadane 8 maja 2018 w C i C++ przez michalnt Użytkownik (520 p.)
0 głosów
2 odpowiedzi 813 wizyt
pytanie zadane 27 lipca 2019 w C# przez TracerYT Początkujący (440 p.)

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...