Okres kolokwiów na połowę semestru ma się już ku końcowi, zatem czas wrócić do normalnego trybu pracy.
Podstawy Programowania na PWr, lekcja 4.
Dziedziczenie
Na początek złota myśl: (pod koniec będzie lepsza) "Jeżeli nie ma konstruktora, wywołany zostaje konstruktor domniemany". Złota myśl w sumie tylko dla mnie, bo domniemany i domyślny to ponoć synonimy, ale jeszcze nigdy nie spotkałem się z tym, żeby ktoś nazwał konstruktora domyślnego "domniemanym".
Baboli tym razem dosyć mało, bo bardziej to przypominało wykład, niż ćwiczenia. Mało kodu, więcej gadania.
Przy omawianiu rzutowania powstało coś takiego:
class Punkt {
int x, y;
public Punkt() {...}
}
class Punkt3D extends Punkt {
int z;
public3D() {...}
}
To public3D
to mam nadzieję literówka. Później doszło do samej prezentacji rzutowania:
Punkt p = new Punkt();
Punkt3D p3 = (Punkt3D)p;
p3.x = 1;
p3.y = 2;
p3.z = 3;
Druga linijka ClassCastException
. Po napisaniu tego kwiatka prowadzący zaczął opowiadać o rzutowaniu w górę i w dół, o różnych mechanikach i tak dalej, by nagle po 10 minutach takiego gadania podkreślić byka i powiedzieć, że to się skompiluje, ale nie uruchomi. Szkoda, że większość grupy zdążyła już to przepisać, a przez te parę minut gadania pewnie zasnąć i nawet nie zwrócili na to uwagi. Gdyby nie moja chęć napisania tego sprawozdania, pewnie też bym nie zauważył :P
Następnie przystąpiliśmy do pisania konkretnego kodu. Mamy mieć klasę abstrakcyjną Pracownik
(ale to, że powinna być abstrakcyjna, to najwyraźniej tylko ja wiedziałem) oraz rozszerzające je klasy Urzednik
i Robotnik
. Te dwie klasy różnią się metodą wyliczania pensji, ale sam kod obliczania nie jest potrzebny do życia.
class Pracownik {
private String nazwisko;
private double etat;
public Pracownik(String nazwisko, double etat) {
this.nazwisko = nazwisko;
this.etat = etat;
}
}
class Urzednik extends Pracownik {
private double placaPodst;
private int procPremii;
public Urzednik(String nazwisko, double etat, double placa, int proc) {
this.placaPodst = placa;
this.procPremii = proc;
super(nazwisko, etat);
}
public double obliczWyplate() {
...
return w;
}
}
Wszystko spoko, poza konstruktorem Urzednik
i super
na końcu zamiast na początku, co da nam błąd, z którym nie zgodzi się nawet kompilator (prowadzący przedstawia do tej pory wszystkie sytuacje tak, jakby kompilator był łagodny jak baranek i brał wszystko jak leci, a wredna VM rzuca nam jakimiś wyjątkami)..
Klasa Robotnik
wyglądała dobrze (nawet super
był w dobrym miejscu), ale zaciekawiło mnie, gdy zaraz po napisaniu pól składowych:
class Robotnik extends Pracownik {
private double stawkaGodz;
private double przepGodz;
private final double limit = 200;
...
public double obliczWyplate() {
...
return w;
}
}
Pan prowadzący powiedział, że zmienna z atrybutem final
jest stała, więc... musi mieć z góry podaną wartość. Ktoś tu pomylił się ze static final
.
Następnie padło zadanie: Napisać klasę przechowującą wszystkich pracowników w jednej tabeli. Dodatkowo klasa ta ma zawierać metodę obliczającą sumę wypłat Robotników. Postanowiłem zbawić dzisiejsze zajęcia i zgłosiłem się do odpowiedzi, funkcja zliczająca wyglądała mniej-więcej tak:
(nazwa metody została mi wymuszona, sorry)
public double sumaWypRob() {
double suma = 0.0;
for (int i = 0; i < tab.length; i++) {
if (tab[i] instanceof Robotnik) {
Robotnik r = (Robotnik)tab[i];
suma += r.obliczWyplate();
}
}
System.out.println(suma);
return suma;
}
Dlaczego przed return
dałem wyświetlenie do konsoli? Bo tak pan prowadzący kazał. Połowa funkcji, jakie realizujemy na laboratoriach (z tym samym panem), ma za zadanie jednocześnie zwrócić wartość i wyświetlić w konsoli, co jest mocno wkurzające, gdy wartość z takiej funkcji może być przydatna gdzieś indziej i musimy łamać zasadę DRY, żeby przypadkiem nie wyświetlić jednej linijki dwa razy (raz w kodzie innej funkcji, raz w "teście").
Na koniec pan prowadzący powiedział, że cały blok if
można by też zastąpić prostym suma += tab[i].obliczWyplate();
. Mniejsza o to, że nie sumuje to pensji samych robotników, a wszystkich pracowników. Ważniejsze jest IMHO to, że obliczWyplate()
nie istnieje w klasie Pracownik
.
Na sam koniec tego mojego (słusznego chyba) bólu odbytu poprawna złota myśl, która pojawiła się na początku wykładu razem z omawianiem pojęcia dziedziczenia:
Dziedziczenie uaktywnia programowanie, czego nie było w programowaniu klasycznym, proceduralnym.