Cześć. Jestem bardzo początkujący i mam taki problem:
mam klasę Pracownik i chcę wpisać takie argumenty, by każdy Pracownik był albo pracownikiem fizycznym albo pracownikiem umysłowym. Jak to zrobić? Jakieś pomysły. Będę wdzięczny za odpowiedź.
Cześć. Jestem bardzo początkujący i mam taki problem:
mam klasę Pracownik i chcę wpisać takie argumenty, by każdy Pracownik był albo pracownikiem fizycznym albo pracownikiem umysłowym. Jak to zrobić? Jakieś pomysły. Będę wdzięczny za odpowiedź.
Albo zrób zmienna boolean która będzie definiowała typ pracownika.
Masz dwie drogi. Pierwsza oparta o enumy, która jest prosta i przyjemna, ale działa tylko wtedy, gdy flagę taką wykorzystujesz jedynie do generowania klasy css. Zazwyczaj kończy się, to kodem w rodzaju:
if(pracownik.isFizyczny()){
//...
} else if(pracownik.isUmysłowy()){
//...
} else{}
w dodatku taki kod rozprzestrzenia się po całym projekcie.
Dlatego jeżeli z tymi typami pracowników jest powiązana jakaś logika, to należy klasycznie dziedziczeniem:
class Pracownik{}
class PracownikFizyczny extends Pracownik{}
class PracownikUmysłowy extends Pracownik{}
Potem w kodzie zamiast if-ów masz metody przyjmujące różne typy i niech kompilator martwi się, co tam dokładnie pod spodem należy wykonać.
lukasz1988 napisał(a):
Albo zrób zmienna boolean która będzie definiowała typ pracownika.
Dla ludzi z takimi pomysłami jest specjalne miejsce w piekle! ;>
Koziołek napisał(a):
Masz dwie drogi. Pierwsza oparta o enumy, która jest prosta i przyjemna, ale działa tylko wtedy, gdy flagę taką wykorzystujesz jedynie do generowania klasy css. Zazwyczaj kończy się, to kodem w rodzaju:
if(pracownik.isFizyczny()){ //... } else if(pracownik.isUmysłowy()){ //... } else{}
w dodatku taki kod rozprzestrzenia się po całym projekcie.
Dlatego jeżeli z tymi typami pracowników jest powiązana jakaś logika, to należy klasycznie dziedziczeniem:
class Pracownik{} class PracownikFizyczny extends Pracownik{} class PracownikUmysłowy extends Pracownik{}
Potem w kodzie zamiast if-ów masz metody przyjmujące różne typy i niech kompilator martwi się, co tam dokładnie pod spodem należy wykonać.
Dróg jest więcej niż dwie.
Zgadzam się, że Twoja druga propozycja lepsze rozwiązanie niż pierwsza, ale co w momencie, gdy poza podziałem na pracowników fizycznych i umysłowych dojdzie jeszcze inny, np. na menadżerów i podwładnych, stałych i kontraktowych, etc.?
Tego już nie da się wcisnąć w drzewiastą hierarchię dziedziczenia, więc zostaniemy z tym, że jeden podział "żyje" w formie hierarchii klas, a pozostałe i tak zmuszeni jesteśmy obsługiwać flagami, czy jakąś inną alternatywą. I zawsze będzie to nieco dezorientujące.
Z tego względu najbardziej godnym polecenia rozwiązaniem jest chyba w ogóle zastąpienie dziedziczenia kompozycją / delegacją, np. z użyciem wzorca dekorator. Dla początkujących: https://en.wikipedia.org/wiki/Decorator_pattern#Java
Muszę przyznać że ja jestem coraz bardziej krytyczny jestem wobec dziedziczenia i traktuję je jako zło konieczne.
Akurat dekorator jest słabym rozwiązaniem jeżeli chcesz dodawać nowe funkcjonalności. Klasa Manager
prawie na pewno będzie posiadała nowe metody i pola. Zatem nie opędzisz tego dekoratorem, ponieważ ten nie może modyfikować API. Jednak dobrze, że wspomniałeś o tym wzorcu, bo należy pamiętać, iż dziedziczenie oznacza dodawanie funkcjonalności, a nie tylko modyfikację istniejących. W przypadku modyfikacji dekorator będzie OK.
No oczywiście masz rację, ale jeśli jest potrzebne dodanie nowych metod, to i tak zawsze można stworzyć osobną klasę (Manager
), która jednak nie będzie dziedziczyć z Employee
, ale wspierać jego interfejs i wywołania "starych" metod delegować, po drodze robiąc jakieś fikuśności. To wciąż podejście elastyczniejsze, niż zwyczajne dziedziczenie.
Jak to mówią, your mileage may vary i zależnie od szczegółów implementacji mogą przeważyć zalety takiego czy innego podejścia. Warto - jak mi się zdaje - po prostu pamiętać, że i takie rozwiązanie mamy w swej dyspozycji. A moja ogólna "reguła kciuka" jest taka, żeby nie sięgać po dziedziczenie odruchowo, jako pierwszą dostępną opcję, tylko po odrzuceniu innych sposobów.
Bo chociaż tutoriale ćwiczą początkujących programistów w tym, by sięgali po nie lekką ręką, na dłuższą metę ma ono swój koszt. Po jakimś czasie może się nam zrobić trudna w refaktoryzacji struktura, niełatwy debugging (skakanie w głąb i do góry po hierarchii), problemy typu fragile base class. Trochę przekonali mnie do tego sceptycyzmu adwokaci programowania funkcyjnego.