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ź.
Zrób sobie jakiś enum w którym zdefiniujesz 2 stałe.
Następnie w klasie pracownik dodaj to pole.
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.