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

Interfejs jako kontrakt

0 głosów
110 wizyt
pytanie zadane 15 grudnia 2018 w Java przez itcloud Gaduła (3,310 p.)
edycja 15 grudnia 2018 przez itcloud
Mówi się, ze programista opiera się na interfejsie pisząc aplikację, bo tak jest łatwiej, bo inny człowiek z zespołu może zająć się konkretną implementacją, a Ty masz wiedzieć tylko, że ktoś ją wykona blablabla.

Nie rozumiem tego do końca, bo żeby móc przetestować tę aplikację nie mogę sobie pisać tylko że jest jakaś tam metoda i ona ma zwracać listę stringów, bo program po odpaleniu nie wykona czegoś tam, bo nie ma implementacji? Gubię się szczerze mówiąc.

np.

jesli stosuje interfejsy jako typy a po prawej stronie klasę:

Collection<String> costam = ArrayList<>();

to rozumiem że mogę podczas gdy to costam ma być argumentem innej funkcji, tak naprawdę zmieniać implementację, np. z ArrayList na HastSet itd. Ale gdzie tu ten wymóg używania wszystkich nazw metod z interfejsu? Kursy mówią o tym, że jak implementujesz interfejs musisz zrobić przepis, dać logikę, implementację wszystkich metod które się w nim znajdują.

A ja jeśli tworzę kolejne funkcje które mają argument jako wyżej wskazany interfejs np.

void print(Collection<string> costam){   }

to tak jak pisałem rozumiem, że wewnątrz tej metody mogę korzystać z różnych implementacji, ale to nie znaczy że musże w tych implementacjach wykorzystać wszystkie możliwe metody, które są wypisane w interfejsie jako wstępne deklaracje?

1 odpowiedź

+1 głos
odpowiedź 15 grudnia 2018 przez Aisekai Nałogowiec (36,150 p.)
wybrane 15 grudnia 2018 przez itcloud
 
Najlepsza

Posługując się interfejsem, sprawiasz że nie obchodzi Cię konkretna implementacja danego zachowania tylko fakt, że jakiś obiekt przejawia dane zachowanie.

Jeżeli dana metoda działa na polu danej klasy, to przed jej wywołaniem musisz mieć utworzony dany obiekt (inaczej dostaniesz NPE). W tym przypadku, najlepiej się posługiwać dependency injection i podczas tworzenia obiektu danej klasy, podać konkretną implementację interfejsu. 

W sytuacji gdy argumentem metody jest obiekt typu interfejsowego (type of an interface) to problem się rozwiązuje w zasadzie sam.

Korzystając z interfejsów, obchodzi Cię jedynie to że dany obiekt przejawia jakieś zachowanie (obiekt implementuje metodę). Dopiero podczas testowania/uruchamiania aplikacji musisz mieć zapewnioną implementację zachowania tworząc konkretny obiekt.

Ale gdzie tu ten wymóg używania wszystkich nazw metod z interfejsu? Kursy mówią o tym, że jak implementujesz interfejs musisz zrobić przepis, dać logikę, implementację wszystkich metod które się w nim znajdują.
 

Wymóg wprowadza kompilator. Jeżeli uważasz, że jakaś klasa powinna zaimplementować dany interfejs, ale nie "powinna" mieć jakiejś metody tzn, że twój interfejs łamie zasadę Single Responsibility.  W sytuacji, gdy masz interfejs ale często implementacje tej metody będą takie same, możesz posłużyć się defaultowymi metodami. 

1
komentarz 15 grudnia 2018 przez miro Pasjonat (19,910 p.)

akaś klasa powinna zaimplementować dany interfejs, ale nie "powinna" mieć jakiejś metody tzn, że twój interfejs łamie zasadę Single Responsibility

Raczej powiedziałbym, że łamie Interface segregation principle, a pochodną tego jest klasa łamiąca Single Respnsibility bo jest zmuszona mieć metody, które nic nie będą robić. 

komentarz 15 grudnia 2018 przez itcloud Gaduła (3,310 p.)

@Aisekai, jeżeli dana metoda działa na polu danej klasy, to przed jej wywołaniem musisz mieć utworzony dany obiekt (inaczej dostaniesz NPE). W tym przypadku, najlepiej się posługiwać dependency injection i podczas tworzenia obiektu danej klasy, podać konkretną implementację interfejsu. 

a możesz to zilustrować przykładem, bo nie wiem czy dobrze rozumiem.

W skrócie, gubię się z tym od strony praktycznej. W tym co wyżej napisałem jako przykład kodu.

1
komentarz 15 grudnia 2018 przez Aisekai Nałogowiec (36,150 p.)

Najprostsze na co wpadłem:

public class Main3 {
    public static class Group {
        Collection<String> students;

        public Group(Collection<String> students) {
            this.students = students;
        }

        public void printStudents() {
            students.forEach(System.out::println);
        }
    }

    public static void main(String[] args){
        String[] students = {"Asia","Kasia","Piotrek","Janek"};
        Group group1 = new Group(Arrays.asList(students));
        group1.printStudents();

        Group group2 = new Group(Set.of(students));
        group2.printStudents();
    }
}

W tym przypadku, jak widzisz nie ma znaczenia czy do konstruktora podam Set czy List, studenci i tak zostaną wypisani. Jako, że wymogiem utworzenia obiektu Group jest podanie w konstruktorze Collections, pozbyłem się sytuacji wywołania metody przed zainicjowaniem pola students. Dodatkowo, stosując DI mogę w bardzo prosty sposób tworzyć obiekty Group z różną implementacją Collection.

Podobne pytania

0 głosów
2 odpowiedzi 94 wizyt
pytanie zadane 24 czerwca 2017 w Java przez ewazdomu Początkujący (320 p.)
0 głosów
3 odpowiedzi 630 wizyt
pytanie zadane 10 maja 2015 w Java przez rubesom Obywatel (1,640 p.)
0 głosów
4 odpowiedzi 277 wizyt
pytanie zadane 20 stycznia w Systemy operacyjne, programy przez Byczek_ Bywalec (2,540 p.)
Porady nie od parady
Możesz ukryć, zamknąć lub zmodyfikować swoje pytanie, za pomocą przycisków znajdujących się pod nim. Nie krępuj się poprawić pochopnie opublikowanego pytania czy zamknąć go po uzyskaniu satysfakcjonującej odpowiedzi. Umożliwi to zachowanie porządku na forum.Przyciski pytania

64,950 zapytań

111,425 odpowiedzi

234,495 komentarzy

46,784 pasjonatów

Przeglądających: 197
Pasjonatów: 12 Gości: 185

Motyw:

Akcja Pajacyk

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

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...