Klasy abstrakcyjne

0

Nie łapię jednej rzeczy. Z tego co się dowiedziałem jeżeli nie mamy niczego sensownego do "zlecenia" metodzie w klasie bazowej, to możemy zaimplementować ją jako klasę abstrakcyjną i tam wrzucić tą metodę. Ale moje pytanie brzmi: skoro nie faktycznie nie mamy sensownej definicji dla metody to na cholerę taką metodę w ogóle tworzyć ? I tak w klasach pochodnych będę musiał na nowo pisać void nazwa_metody blablabla. Załączam zrzut z mojej książki z tym niejasnym dla mnie fragmentem.

9

Jaka jest rozdzielczość monitora? - to pytanie nie ma sensu (jeżeli w kontekście mielibyśmy np mój lub Twój monitor, wtedy z niego moglibyśmy wyciągnąć taką informację, mój ma 17' a Twój powiedzmy 18,3').

Pytanie Jaką rozdzielczość ma MÓJ monitor - to pytanie ma sens (chodzi o mój konkretny monitor i mogę sprawdzić jaką ma rozdzielczość, podobnie jak pytanie Jaką rozdzielczość ma TWÓJ monitor).

Monitor musi mieć metodę Monitor.jakaJestRozdzielczość(), ponieważ każdy monitor jakąś ma. Niestety nie może ona być zaimplementowana, bo na pytanie Jaką rozdzielczość ma monitor (nie konkretny, tylko monitor w ogóle) nie da się odpowiedzieć. Żeby na nie odpowiedzieć potrzebujesz wiedzieć o jaki monitor chodzi.

--- Praktyka ----
Teraz wystarczy to odnieść do programowania.

Jeżeli chcesz zrobić coś takiego

MojMonitor moj = new MojMonitor();

to faktycznie ta metoda "niezaimplementowana" nie ma sensu. Sens jednak pojawia się wtedy kiedy chcesz użyć monitora, ale do wyboru masz jeden albo drugi (to jest polimorfizm).

abstract class Monitor {
    abstract float getResolution(); // metoda nie może mieć ciała bo skąd mamy wiedzieć jaką rozdzielczość ma monitor w ogóle
}
class MojMonitor extends Monitor {
    float getResolution() {
      return 17.1;
    }
}
class TwojMonitor extends Monitor {
    float getResolution() {
      return 18.3;
    }
}
Monitor moj = new MojMonitor();
Monitor twoj = new TwojMonitor();

printResolution(moj); // wypisze 17.1
printResolution(twoj); // wypisze 18.3
void printResolution(Monitor jakisMonitor) {
    System.out.println(jakisMonitor.getResolution()); // Monitor musi miec metode getResolution bo każdy monitor ma jakąś rozdzielczość
}
2

To co napisał @TomRiddle jest jak najbardziej właściwe jednak tak naprawdę osoba dopiero się ucząca nadal może nie rozumieć jaki w tym sens. Kluczem w tamtym przykładzie jest ostatni element, czyli metoda przyjmująca argument typu Monitor. Musisz wziąć pod uwagę że w programach posiadające często setki klas nie da się odnosić do poszczególnych klas dziedziczących. Co za tym idzie możesz mieć metodę przyjmującą typ bazowy (w tym przypadku Monitor) który gwarantuje że przekazany obiekt będzie dostarczał funkcjonalność zapewnianej przez typ Monitor. To czego instancją jest przekazany obiekt nie ma już wtedy znaczenia, może to być MojMonitor, TwojMonitor czy cokolwiek innego. Ciebie interesuje tylko to aby wywołać metodę getResolution() na tym obiekcie.

Już to chyba kiedyś pisałem w innym wątku na tym forum. Na początku nauki programowania trzeba pamiętać że opisy tych różnych zagadnień to tylko wprowadzenie do mechanizmów i wielokrotnie nie będziesz widział sensu w ich używaniu. Chodzi o to byś w ogóle wiedział jak coś zrobić, niekoniecznie byś zawsze widział w tym sens. Warto przyjąć zasadę "wiem że nic nie wiem", skupić się na nauce mechanizmów a sens ich używania przyjdzie z czasem.

1

to na cholerę taką metodę w ogóle tworzyć

Bo dzięki temu w kodzie mozesz używać "klasy bazowej" i jednocześnie móc wołać z niej tą metodę. Ćwiczenie dla ciebie: napisz funkcje która przymuje listę obiektów klasy Person i wypisuje description każdej z nich. Powiedzmy że będzie to jakieś:

List<Person> people = Arrays.asList(new Studet(), new Studet(), new Employee(), new Employee());

Spróbuj to teraz zrobić BEZ definiowania getDescription() jako metody w klasie Person a następnie dodajac tam tą metodę.

0

Dzięki chłopaki, zaczynam widzieć w tym sens. Póki co na moim etapie zaawansowania zapewne nie dostrzegam wszystkich plusów i możliwości tego zabiegu, ale liczę, że z czasem stosowanie tego będzie mi przychodziło naturalnie.

Już to chyba kiedyś pisałem w innym wątku na tym forum. Na początku nauki programowania trzeba pamiętać że opisy tych różnych zagadnień to tylko wprowadzenie do mechanizmów i wielokrotnie nie będziesz widział sensu w ich używaniu. Chodzi o to byś w ogóle wiedział jak coś zrobić, niekoniecznie byś zawsze widział w tym sens. Warto przyjąć zasadę "wiem że nic nie wiem", skupić się na nauce mechanizmów a sens ich używania przyjdzie z czasem.

Tak, to prawda. Zauważyłem to wcześniej. Wychodzę z założenia żebym umiał to zastosować na prostym przykładzie, a w przyszłości będę wiedział, że coś takiego istnieje i do którego momentu się cofnąć, żeby o tym doczytać.

Bo dzięki temu w kodzie mozesz używać "klasy bazowej" i jednocześnie móc wołać z niej tą metodę. Ćwiczenie dla ciebie: napisz funkcje która przymuje listę obiektów klasy Person i wypisuje description każdej z nich.

Wolę tablice. Ale to chyba będzie coś takiego ?

abstract class Person{
    String x;
    
    abstract String getDescription();
    
}

class Student extends Person { 
    Student (String name){
        x = name;
    }
    String getDescription() {
        return x;
    }
}

class Employye extends Person { 
    Employee (String name) {
        x = name;
    }
    String getDescription() {
        return x;
    }
}

class Lecturer extends Person {
    Lecturer (String name) {
        x = name;
    }
    String getDescription() {
        return x;
    }
}

public class Main {
    
    public static void main(String[] args){
        
        Person person[] = new Person[5];
        
        person[0] = new Student("Janusz");
        person[1] = new Employye("Pani Krystyna");
        person[2] = new Lecturer("Wykladowca ochrony srodowiska");
        person[3] = new Employee("Pani Zofia");
        person[4] = new Student("Krzysiek");
        
        for (int i = 0; i < person.length; i++) {
            System.out.println(person[i].getDescription());
        }
    }
    
}

Spróbuj to teraz zrobić BEZ definiowania getDescription() jako metody w klasie Person a następnie dodajac tam tą metodę.

Można jeszcze w ten sposób:

abstract class Person{
	 String x;
	
	//abstract String getDescription();
	
	 String ZwrocX(Person person){
		return x;
	}
	
}

i w mainie:

for (int i = 0; i < person.length; i++) {
	System.out.println(person[i].ZwrocX(person[i]));
}
1

No ale przecież cały czas bazujesz na tym że Person ma metodę która zwraca to co chcesz ;] A jeśli to coś nie jest parametrem ani nie jest wspólne dla obu pod-klas ani nie jest wartością pola nadklasy?
Załóżmy że chcesz mieć metodę getSalary() która zwraca pensje danej osoby. Pensja jest liczona w zupełnie inny sposób dla każdego typu osoby. Jak wtedy sobie poradzisz bez metody abstrakcyjnej w nadklasie? ;]
Załóż np. że Student ma zawsze salary 0, Lecturer ma 1000liczba liter w imieniu a Employee (tak sie to pisze ;) ) ma 1000liczba samogłosek w imieniu.

0
Shalom napisał(a):

Załóżmy że chcesz mieć metodę getSalary() która zwraca pensje danej osoby. Pensja jest liczona w zupełnie inny sposób dla każdego typu osoby. Jak wtedy sobie poradzisz bez metody abstrakcyjnej w nadklasie? ;]

Racja.

A tamten kod jest dobry, czy tak jak pisze TomRiddle, nie o to chodziło ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1