Dziedziczenie pól to zło? Dlaczego?

Dziedziczenie pól to zło? Dlaczego?

Wątek przeniesiony 2017-08-20 23:32 z Java przez Shalom.

KA
KA
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Warszawa
  • Postów:1683
0

Hej!

W swoim artykule nt. wykorzystywania UID jako id obiektu https://4programmers.net/Forum/1316159 zastosowałam klasę po której miałyby dziedziczyć wszystkie encje JPA ukazaną poniżej:

Kopiuj
import lombok.Getter;
import lombok.ToString;
 
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.UUID;
 
@Getter
@ToString
@MappedSuperclass
public abstract class SimpleEntity implements Serializable {
 
    @Id
    @Column(updatable = false, nullable = false, unique = true)
    private final UUID id = UUID.randomUUID();
 
    @Version
    private Integer version;
 
    private LocalDateTime creationDate;
 
    private LocalDateTime modificationDate;
 
    @PrePersist
    private void prePersist() {
        modificationDate = creationDate = LocalDateTime.now();
    }
 
    @PreUpdate
    private void preUpdate() {
        modificationDate = LocalDateTime.now();
    }
 
    @Override
    public boolean equals(Object that) {
        return this == that || that instanceof SimpleEntity
                && Objects.equals(id, ((SimpleEntity) that).id);
    }
 
    @Override
    public int hashCode() {
        return Objects.hashCode(id);
    }
}

I jest to ładne, cwane i zapewnia nam ładne ID , które wyjaśniłam w podlinkowanym wyżej artykule. Tymczasem dzisiaj natknęłam się na taki film:

w którym to Pan mówi dziedziczyć należy zachowania klas a straszną głupotą jest dziedziczenie pól. dziedziczenie nie powstało po to żeby dziedziczyć pola. zachowania wspólne się dziedziczy a na pewno nie pola . Więc w takim razie dlaczego nie wolno dziedziczyć pól i jakie minusy ma dziedziczenie pól jak w przykładzie podanym przeze mnie wyżej (klasa SimpleEntity). Pytam, bo odkryłam nową rzecz i całkowicie tego nie rozumiem dlaczego dziedziczenie pól jest be? Czy ten gość przesadza czy ma rację?


PROGRAMY NA ZAMÓWIENIE, ZALICZENIA STUDENCKIE, KONFIGURACJA SERWERÓW, SYSTEMÓW I BAZ DANYCH, STRONY INTERNETOWE, POMOC W PROGRAMOWANIU, POPRAWIENIE I OPTYMALIZACJA APLIKACJI
JAVA, C++, LINUX, WWW, SQL, PYTHON
POSIADAM KOMERCYJNE DOŚWIADCZENIE
TANIO, SZYBKO I PORZĄDNIE
Z KOMENTARZAMI OBJAŚNIAJĄCYMI KOD
PISZ NA PRYWATNĄ WIADOMOŚĆ
CENY JUŻ OD 49,99ZŁ ZA PROGRAM
ZAJMIJ SIĘ TYM CO CIĘ NAPRAWDĘ INTERESUJE!
Schadoow
  • Rejestracja:około 13 lat
  • Ostatnio:około 13 godzin
  • Postów:1064
0

Czytałaś stacka na ten temat ;p ?

KA
KA
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Warszawa
  • Postów:1683
4

nie bo 4programmers > stackvoerflow


PROGRAMY NA ZAMÓWIENIE, ZALICZENIA STUDENCKIE, KONFIGURACJA SERWERÓW, SYSTEMÓW I BAZ DANYCH, STRONY INTERNETOWE, POMOC W PROGRAMOWANIU, POPRAWIENIE I OPTYMALIZACJA APLIKACJI
JAVA, C++, LINUX, WWW, SQL, PYTHON
POSIADAM KOMERCYJNE DOŚWIADCZENIE
TANIO, SZYBKO I PORZĄDNIE
Z KOMENTARZAMI OBJAŚNIAJĄCYMI KOD
PISZ NA PRYWATNĄ WIADOMOŚĆ
CENY JUŻ OD 49,99ZŁ ZA PROGRAM
ZAJMIJ SIĘ TYM CO CIĘ NAPRAWDĘ INTERESUJE!
PI
  • Rejestracja:ponad 9 lat
  • Ostatnio:3 miesiące
  • Postów:2787
0

Wtf? Przecież dziedziczenie powstało właśnie po to żeby wspólne POLA mieć w wyższej warstwie abstrakcji xd prostokąt ma obwód? Ma. Koło ma obwód? Ma. No to wniosek - "obwód" to pole klasy Figura, szkolny przykład

T9
  • Rejestracja:prawie 10 lat
  • Ostatnio:prawie 6 lat
  • Postów:329
3

Wtf? Przecież dziedziczenie powstało właśnie po to żeby wspólne POLA mieć w wyższej warstwie abstrakcji xd prostokąt ma obwód? Ma. Koło ma obwód? Ma. No to wniosek - "obwód" to pole klasy Figura, szkolny przykład

Bez sensu i po co komu pole z obwodem prostokąta lub kwadratu, będziesz podawał obwód przez konstruktor i na jego podstawę obliczał boki ? xD

edytowany 1x, ostatnio: topik92
nie100sowny
  • Rejestracja:prawie 9 lat
  • Ostatnio:4 dni
  • Lokalizacja:Kraków
  • Postów:402
1

Po pierwsze to w tej super klasie pola powinny być chyba protected.

Dziedziczenie to zło.

  1. Narusza hermetyzację.
  2. Zmusza autora do przeczytania całego kodu klasy bazowej.
  3. Jest bardzo sztywną relacją - wykluczającą dynamiczne zmiany.
  4. Przy dziedziczeniu bardzo trudno uniknąć złamania zasady Liskov.
  5. Wprowadza dodatkowe komplikacje przy metodach equals / hashCode. Komplikuje kolejność inicjalizacji pól klasy itp.

Nie potrafię znaleźć jednak argumentu, że dziedziczenie pól jest złe.
Przeglądam Internety i nic nie mogę znaleźć, choć teza się czasem przewija.
Na chłopski rozum co mi przychodzi to być może następujące uogólnienie:

Dziedziczenie jest złe. --> Tylko dziedziczenie zachowań (interfejsów) ma sens. --> Dziedziczenie pól w takim razie nie ma sensu.

EDIT: Może ktoś bardziej doświadczony się odezwie :) Chociaż oni podobno już tylko funkcyjnie w Scali jadą :P


"Gdy się nie wie, co się robi, to się dzieją takie rzeczy, że się nie wie, co się dzieje"
edytowany 4x, ostatnio: nie100sowny
V-2
"Zmusza autora do przeczytania całego kodu klasy bazowej" - jeżeli rzeczywiście do tego zmusza, to zostało użyte bardzo nieporadnie
Julian_
jeśli dziedziczenie to zło to całe programowanie obiektowe jest do niczego.
nie100sowny
Baa, programowanie w ogóle jest do niczego @Julian_.
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 8 godzin
0

Nie chce mi się oglądać prawie 2 godzinnego nagrania, a nie widzę tu w wątku podanej wprost argumentacji tłumaczącej dlaczego dziedziczenie pól to zło.

Z polami w Javie jest taki problem, że nie da się nadpisać pola z klasy nadrzędnej - można co najwyżej stworzyć pole o takiej samej nazwie i mieć potem problemy z przesłanianiem zmiennych.

Przykład:
http://ideone.com/kDycY9

Kopiuj
import java.util.*;
import java.lang.*;
import java.io.*;
import static java.lang.System.out;
 
class Ideone
{
	static class Base {
		int i;
	}
 
	static class Derived extends Base {
		int i;
	}
 
 
	public static void main (String[] args) throws java.lang.Exception
	{
		Derived derived = new Derived();
		Base base = derived;
		derived.i = 5;
		base.i = 6;
		out.println(derived.i);
		out.println(base.i);
		out.println(((Base) derived).i);
		((Base) derived).i = 4;
		derived.i = 3;
		out.println(derived.i);
		out.println(base.i);
		out.println(((Base) derived).i);
	}
}

Scala nie utrudnia dziedziczenia pól. Wręcz przeciwnie - pozwala na ich wielodziedziczenie (z traitów). Podejście Scali do pól jest jednak inne niż w Javie, gdyż zdefiniowanie pola w Scali definiuje z automatu gettera (i potencjalnie settera), a dostęp do pól z klas Scalowych odbywa się tylko z użyciem tych automatycznie stworzonych metod dostępowych.

Konkretniej to jest tak:

Kopiuj
class KlasaBazowa {
  // tutaj stworzone zostanie pole 'stała', ale również metoda 'stała()' która zwraca zawartość pola 'stała'
  val stała = 5;

  // tutaj stworzone zostanie pole 'zmienna', ale również metoda 'zmienna()' zwracająca zawartość pola 'zmienna' oraz metoda 'zmienna_=(zmienna: Int)' służąca do zmiany zawartości pola
  var zmienna = 5;
}

class KlasaDziedzicząca extends KlasaBazowa {
  // tutaj zostanie stworzone nowe pole 'stała', a metoda 'stała()' zostanie nadpisana nową
  override val stała = 6;

  // tutaj zostanie stworzone nowe pole 'zmienna', a metody 'zmienna()' i 'zmienna_=(zmienna: Int)' zostaną nadpisane nowymi
  override var zmienna = 6;
}

class KlasaUżywająca {
  val instancja = new KlasaDziedzicząca();

  // aktualizacja pola 'zmienna' odbywa się przez wywołanie metody 'zmienna_=(8)'
  instancja.zmienna = 8;

  // użycie pola 'zmienna' odbywa się poprzez wywołanie metody 'zmienna()'
  println(instancja.zmienna);
}

Scalowe pola mają więc semantykę zbliżoną do metod wirtualnych. Trzeba pamiętać jednak o kolejności inicjalizacji (która w Scali jak i w Javie odbywa się od klas najogólniejszych, czyli najwyżej w hierarchi, aż do tych najbardziej specyficznych, czyli najniżej w hierarchii), którą da się zaobserwować (zwykle w wyniku błędu w kodzie, ale sporadycznie może to być robione świadomie).

Podobieństwo pól do metod w Scali jest na tyle duże, że można zaimplementować bezargumentową metodę abstrakcyjną za pomocą pola, np:

Kopiuj
abstract class KlasaBazowa {
  def abstrakcyjneCóś: Int
}

class KlasaDziedzicząca extends KlasaBazowa {
  val abstrakcyjneCóś = 5
}

Powyższy trik to częsty idiom w Scali. Z kolei nadpisywanie pól w Scali jest ryzykowne (ze względu na wspomnianą kolejność inicjalizacji), więc jest niezbyt częste, a ja sam staram się tego unikać.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 5x, ostatnio: Wibowit
V-2
  • Rejestracja:prawie 8 lat
  • Ostatnio:9 miesięcy
  • Postów:671
1

Nie mogę wiedzieć na pewno, co akurat ten gość miał na myśli. Ale moim zdaniem chodzi tu raczej o pola zmienne, niż niezmienne.

Innymi słowy o pola, w których klasa trzyma sobie "notatki" na temat swojego własnego stanu, potrzebne do poprawnego działania.

Te "notatki", nawet w rodzinie klas, powinny raczej pozostać rzeczą prywatną.

W przeciwnym wypadku rośnie ryzyko, że klasa pochodna niechcący popsuje coś, co już raz dobrze działało u rodzica - albo odwrotnie, zmiany w klasie bazowej zepsują działanie klas pochodnych. Taki szczególny przypadek fragile base class.

Enkapsulacja obowiązuje nawet w hierarchii dziedziczenia. Szczegóły implementacji nie powinny przeciekać, a dziedziczenie pól (zmiennych) tym właśnie grozi.


Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem, ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia. W drugiej firmie której już pracuję mam palących marihuanę programistów [...] piszą kod "leniwie", często nie wysilając się, rozwlekając ten kod, unikając np. programowania funkcyjnego (mówię tutaj o lambdach w javie).
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
5

Ja rozumiem że chodzi tutaj o to, żeby nie robić pól typu package/protected, tzn takich bezpośrednio dostępnych z klasy podrzędnej i ma to sens. Klasa dziedzicząca nie powinna zależeć od wewnętrznej implementacji klasy, z której dziedziczymy. To sie nazywa tzw "Fragile Base Class Problem", tzn nagle kosmetyczna zmiana w klasie bazowej staje sie niemożliwa bo wysadza całą hierarchie, bo gdzieśtam zależymy od szczegółów klasy bazowej.
Nie różni sie to specjalnie od zwykłej idei hermetyzacji -> powinniśmy uzywać obiektu tylko za pomocą jego interfejsu i absolutnie nie za pomocą grzebania w jego wewnętrznym stanie. I tak samo kiedy dziedziczymy -> w klasie pochodnej używamy metod klasy bazowej a nie odnosimy się bezpośrednio do pól.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 2x, ostatnio: Shalom
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 16 godzin
  • Postów:2367
3

Według mnie nie ma jedynej słusznej odpowiedzi, czy jest złe czy nie. Po prostu to zależy od kontekstu i od tego jakie opcje mamy do rozwiązania konkretnego problemu. Stwierdzenie, że coś jest złe/dobre, to ocenianie, a do tego trzeba mieć jakieś kryteria, a nie po prostu przekonanie.

Przed wprowadzeniem widoczności pola w podklasie trzeba się zastanowić jakie będą konsekwencje i czy są akceptowalne. Jakie kryteria przyjąć? Np. zasady SOLID i ilość złamanych zasad. Jeśli rozwiązanie#1 nie łamie zasad SOLID, a rozwiązanie#2 łamie 1 czy 2 zasady, to z perspektywy projektowej warto wybrać 1.

Tworząc komercyjnie, pracujemy przy dodatkowych ograniczeniach typu czas/pieniądze/istniejące interfejsy/etc. Nie zawsze możemy sobie pozwolić na rozwiązanie#1, które jest lepsze jeśli chodzi o oprogramowanie, ale wymaga większych nakładów czasowych i finansowych.

V-2
Określenie "nakładów czasowych" nie zawsze jest takie proste, bo czas niby przyoszczędzony dziś może być niejako na kredyt, który będzie się spłacać z odsetkami (dług techniczny).
YA
Zgadzam się w 100%, że nie jest to proste. Może być jednak tak, że: i) nie przewidujemy dalszego rozwoju oprogramowania, ii) mamy narzucone ramy czasowy, gdzie rozwiązanie musi być dostarczone. Teraz mam taki przypadek w projekcie, gdzie funkcjonalność jest bardzo ważna z perspektywy wdrożenia oprogramowania i migracji danych, ale będzie używana miesiąc, góra dwa. W moim przypadku spłata ewentualnego (=nie wiem jak zaimplementują) długu technicznego nie będzie potrzebna.
JU
  • Rejestracja:około 22 lata
  • Ostatnio:30 dni
  • Postów:5042
0

Zgadzam się z @yarel
Są sytuacje, w których dziedziczy się pola.

Ale. Na pewno lepszym pomysłem jest dziedziczenie tylko metod, ponieważ pewne mechanizmy mogą kiedyś ulec zmianie w klasie bazowej. I wtedy z dziedziczeniem pola może być taka sama sytuacja jak z upublicznieniem pola. Czyli klasa potomna nagle zacznie robić coś, czego robić nie powinna. W związku z tym zawsze lepiej od początku tworzyć klasę bazową tak, żeby pola nie były dziedziczone. Natomiast są sytuacje, w których można to zrobić i pewnie nigdy niczego to nie zaburzy.

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

@Juhas: o_O pola dziedziczy się ZAWSZE. Jedyne co można ograniczyć to ich WIDOCZNOŚĆ.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
Zobacz pozostałe 10 komentarzy
Shalom
@Afish: nie każdy miał okazję słuchać dra. Dorohinickiego i jego wywodów na temat tożsamości obiektu, self/this, delegacji, przywołania i takich tam :P
AF
W takim razie polecam „A Theory of objects” Abadiego i Cardelliego, może gdyby ludzie „programujących obiektowo” czytali tę pozycję, to przestaliby twierdzić, że w javie nie ma wielodziedziczenia (czy też precyzyjniej wyrażaliby się, jakiego wielodziedziczenia nie ma, a jakie jest).
V-2
@Afish: mógłbyś podać przykład w postaci kodu?
AF
@V-2: Jakiego kodu, skoro Java nie implementuje dziedziczenia w ten sposób? Koncepcyjnie podobne jest dziedziczenie prototypowe w JS, przy czym on jest językiem bezklasowym, więc jest to jeszcze coś innego.
V-2
@Afish: wątek jest o dziedziczeniu w Javie, więc skoro nie zastrzegłeś inaczej, to wyglądało że o to ci chodzi.
V-2
  • Rejestracja:prawie 8 lat
  • Ostatnio:9 miesięcy
  • Postów:671
4
Shalom napisał(a):

@Juhas: o_O pola dziedziczy się ZAWSZE. Jedyne co można ograniczyć to ich WIDOCZNOŚĆ.

Oficjalna dokumentacja stosuje to praktyczne rozumienie "dziedziczenia prywatnych pól".

http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html -

A subclass does not inherit the private members of its parent class.

i to w więcej niż jednym miejscu:

https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2

Members of a class that are declared private are not inherited by subclasses of that class.

Oczywiście:

if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass

ale to inna sprawa.

Uważam zatem że nie masz racji, zgodnie z https://stackoverflow.com/a/4716335/168719

Dziedziczenie jest po prostu rozumiane jako "oddanie do bezpośredniej dyspozycji".


Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem, ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia. W drugiej firmie której już pracuję mam palących marihuanę programistów [...] piszą kod "leniwie", często nie wysilając się, rozwlekając ten kod, unikając np. programowania funkcyjnego (mówię tutaj o lambdach w javie).
edytowany 2x, ostatnio: V-2
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
2

@V-2 to jest trochę kwestia kosmetyki, bo chodzi tutaj o rozróżnienie między obiektem a klasą. W tym ujęciu klasa pochodna faktycznie nie dziedziczy prywatnych pól klasy bazowej, ale obiekt tejże klasy jak najbardziej, co zresztą wynika wprost z Zasady Podstawiania Liskov.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
V-2
  • Rejestracja:prawie 8 lat
  • Ostatnio:9 miesięcy
  • Postów:671
4

Tak to tłumaczy odpowiedź na SO... Ja i nad tym bym się zastanawiał, czy w ogóle można mówić, że obiekt (jako instancja) cokolwiek dziedziczy; czy to nie jest tylko skrót myślowy na określenie tego, że jego klasa coś dziedziczy. Ale to są oczywiście takie dywagacje semantyczno-definicyjne. Każdy powinien rozumieć, że do prywatnych pól rodzica nie ma z poziomu kodu dostępu... ale też nie dziwić się, że zobaczy je w debuggerze jak sobie rozwinie zawartość obiektu-dziecka.


Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem, ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia. W drugiej firmie której już pracuję mam palących marihuanę programistów [...] piszą kod "leniwie", często nie wysilając się, rozwlekając ten kod, unikając np. programowania funkcyjnego (mówię tutaj o lambdach w javie).
wiewiorek
  • Rejestracja:prawie 17 lat
  • Ostatnio:10 dni
0

Też słyszałem, że nie powinno dziedziczyć się pól - nie znam jednak argumentów za tym przemawiających. Czy ma ktoś linka do podobnej dyskusji na stackoverflow? Może tam będą jakieś konkretne argumenty?

YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 16 godzin
  • Postów:2367
0
wiewiorek napisał(a):

Też słyszałem, że nie powinno dziedziczyć się pól - nie znam jednak argumentów za tym przemawiających.

Na tych polach przechowywany jest stan obiektu. Stan ten jest wewnętrzną sprawą obiektu i może być przez ten obiekt modyfikowany w odpowiedzi na komunikaty z "zewnątrz".

Jak dajemy dostęp do pól obiektu innym, to tracimy kontrolę nad tym, gdzie ten stan jest zarządzany (tzn. czy w klasie bazowej, czy może w podklasie, czy trochę tu, trochę tam). Utrata kontroli może prowadzić do sytuacji, gdy stan obiektu ulegnie "zepsuciu" i zmieni się zachowanie operacji.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 13 godzin
  • Lokalizacja:Wrocław
2

Ja tam uwielbiam, gdy pola klasy bazowej są prywatne, nie ma dostępu do żadnych zależności, w dziecku niczego nie da się normalnie nadpisać, i trzeba jechać refleksją albo kopiować całą klasę po to tylko, żeby zmienić jedną małą rzecz.
Naprawdę, myślę wtedy, że autor jest nieskończenie wybitnym programistą. ;)

nie100sowny
Po tym wpisie zacznę mieć koszmary, że trafiłem do Twojego zespołu :P
nie100sowny
  • Rejestracja:prawie 9 lat
  • Ostatnio:4 dni
  • Lokalizacja:Kraków
  • Postów:402
0

@somekind Twój post dowodzi, że dziedziczenie powinno być zakazane.

Jak już pisałem wcześniej, gdy dziedziczysz po klasie to MUSISZ ją przeczytać i zrozumieć (wujek Bob to dowodzi). Dlatego gdy już zrozumiesz klasę bazową to albo nie dotykasz tego pola private i wiesz dlaczego, albo zmieniasz na protected.

Pomysł z refleksją to płacz pokoleń, które po Tobie to będą debugować.


"Gdy się nie wie, co się robi, to się dzieją takie rzeczy, że się nie wie, co się dzieje"
katelx
  • Rejestracja:prawie 10 lat
  • Ostatnio:4 miesiące
  • Lokalizacja:Hong Kong
1
karolinaa napisał(a):

dlaczego dziedziczenie pól jest be? Czy ten gość przesadza czy ma rację?

nie da sie nie dziedziczyc pol :) dziedziczenie jest ok o ile jest wynikiem przemyslen a nie lenistwa

nie100sowny napisał(a):
  1. Narusza hermetyzację.

nie powinno tak byc, wystarczy ze metody w klasie pochodnej nie maja efektow ubocznych i tyle :)

  1. Zmusza autora do przeczytania całego kodu klasy bazowej.

to oznacza ze dziedziczenie nie powinno wchodzic w gre, tzn klasa bazowa nie zostala stworzona z zalozeniem ze bedzie z niej dziedziczone

  1. Jest bardzo sztywną relacją - wykluczającą dynamiczne zmiany.

dlatego wlasnie imo powinno sie oznaczac wszystkie klasy jako final, chyba ze tworzymy klase celowo pod katem dziedziczenia z niej

  1. Przy dziedziczeniu bardzo trudno uniknąć złamania zasady Liskov.

racja, dlatego wlasnie dziedziczenie powinno byc raczej ostatecznoscia niz domyslnym rozwiazaniem

  1. Wprowadza dodatkowe komplikacje przy metodach equals / hashCode. Komplikuje kolejność inicjalizacji pól klasy itp.

imo jesli klasa wymaga equals/hashCode to znaczy ze powinna byc final i nie miec extends

Nie potrafię znaleźć jednak argumentu, że dziedziczenie pól jest złe.

ehh, zawsze dziedziczy sie pola. zla jest ich modyfikacja w klasie pochodnej.

Dziedziczenie jest złe. --> Tylko dziedziczenie zachowań (interfejsów) ma sens

to jest dobra regula dla newbies ;) po prostu trzeba zachowac zdrowy rozsadek i tyle

somekind napisał(a):

Ja tam uwielbiam, gdy pola klasy bazowej są prywatne, nie ma dostępu do żadnych zależności, w dziecku niczego nie da się normalnie nadpisać, i trzeba jechać refleksją albo kopiować całą klasę po to tylko, żeby zmienić jedną małą rzecz.
Naprawdę, myślę wtedy, że autor jest nieskończenie wybitnym programistą. ;)

zawsze mozesz zrobic w klasie bazowej sprawdzic wlasciwy typ this i zmienic spersonalizowac zachowanie pod katem dziecka ;)

Jak już pisałem wcześniej, gdy dziedziczysz po klasie to MUSISZ ją przeczytać i zrozumieć (wujek Bob to dowodzi).

bzdura

somekind
100% racji. Albo klasa pozwala na dziedziczenie, albo nie, nie można być w połowie rodzicem.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 13 godzin
  • Lokalizacja:Wrocław
2
nie100sowny napisał(a):

Jak już pisałem wcześniej, gdy dziedziczysz po klasie to MUSISZ ją przeczytać i zrozumieć (wujek Bob to dowodzi). Dlatego gdy już zrozumiesz klasę bazową to albo nie dotykasz tego pola private i wiesz dlaczego, albo zmieniasz na protected.

Nie zmienię modyfikatora pola na protected w zewnętrznej bibliotece, chyba że skopiuję kod albo zrobię forka. Pierwsze jest nieeleganckie, drugie jest nadmiernym wysiłkiem. Dlatego tak lubię programistów, którzy piszą w ten sposób.

Jak dla mnie są dwie możliwości na poziomie projektowym:

  • albo pozwalamy dziedziczyć ze swojej klasy, i wtedy wszystkie pola ustawiamy od razu jako protected, albo dajemy jakiś inny dostęp do nich (np. przez metodę).
  • albo nie wspieramy dziedziczenia z klasy, wtedy klasę plombujemy i nikt z niej nie dziedziczy.

Pomysł z refleksją to płacz pokoleń, które po Tobie to będą debugować.

Jeśli pomyślałeś, że ja chcę używać refleksji do kodu, który posiadam, to tak naprawdę nie pomyślałeś.

KA
KA
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Warszawa
  • Postów:1683
0
katelx napisał(a):

dlatego wlasnie imo powinno sie oznaczac wszystkie klasy jako final, chyba ze tworzymy klase celowo pod katem dziedziczenia z niej

Według mnie też klasy, które nie są nastawione pod dziedziczenie powinny być final i według najlepszych hakerek też.
Tak samo bodajże Joshua Blocha pisał o tym w Effective Java 2.

katelx napisał(a):

imo jesli klasa wymaga equals/hashCode to znaczy ze powinna byc final i nie miec extends

@katelx aaa klasa SimpleEntity z przykładu z pierwszej strony mojego wątku?


PROGRAMY NA ZAMÓWIENIE, ZALICZENIA STUDENCKIE, KONFIGURACJA SERWERÓW, SYSTEMÓW I BAZ DANYCH, STRONY INTERNETOWE, POMOC W PROGRAMOWANIU, POPRAWIENIE I OPTYMALIZACJA APLIKACJI
JAVA, C++, LINUX, WWW, SQL, PYTHON
POSIADAM KOMERCYJNE DOŚWIADCZENIE
TANIO, SZYBKO I PORZĄDNIE
Z KOMENTARZAMI OBJAŚNIAJĄCYMI KOD
PISZ NA PRYWATNĄ WIADOMOŚĆ
CENY JUŻ OD 49,99ZŁ ZA PROGRAM
ZAJMIJ SIĘ TYM CO CIĘ NAPRAWDĘ INTERESUJE!
edytowany 1x, ostatnio: karolinaa
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 16 godzin
  • Postów:2367
0
katelx napisał(a):
  1. Wprowadza dodatkowe komplikacje przy metodach equals / hashCode. Komplikuje kolejność inicjalizacji pól klasy itp.

imo jesli klasa wymaga equals/hashCode to znaczy ze powinna byc final i nie miec extends

np. java.lang.Object ? ;)

danek
ale to nie Object ich wymaga tylko jakieś konkretne inne które sam piszesz
YA
Chyba klucz tkwi w zrozumieniu znaczenia "klasa wymaga equals/hashCode". W myśl tej zasady jak mam Owoc {waga, kolor, smak} to i zdefiniowane equals, to nie mogę przedefiniować equals w Jablko { odmianaJabloni } i Gruszka { odmianaGruszy } i tym samym porównywać różnych owoców? Czy może chodzi o to, że jak mam sortownice do owoców i ona korzysta z equals, to powinna być final?
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4706
2
somekind napisał(a):

Nie zmienię modyfikatora pola na protected w zewnętrznej bibliotece, chyba że skopiuję kod albo zrobię forka. Pierwsze jest nieeleganckie, drugie jest nadmiernym
wysiłkiem. Dlatego tak lubię programistów, którzy piszą w ten sposób.

Taka prostacka reguła mówi, że jeśli zewnętrzna biblioteka wymaga abyś używał dziedziczenia po zdefiniowanych w niej klasach - to nie jest już to bilblioteka, ale framework.
I dlatego też frameworki są do d...y, a bilblioteki rządzą :-)


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 2x, ostatnio: jarekr000000
nie100sowny
Niech Wicket ginie w piekle !!!
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:12 dni
1

Osobiście bardzo lubię podejście z Pythona, gdzie nie ma prywatnych pól, a jedynie oznacza się je przez nazewnictwo. Prywatne pola i klasy final fajnie brzmią na kartce, ale w rzeczywistości i tak kończy się to hakami przy użyciu refleksji. Jak ktoś chce mieć hermetyzację, to niech realizuje ją przez interfejsy, a nie przez ograniczanie wszystkiego; dzięki temu gdy ja zacznę dobierać się do jakichś wewnętrznych składowych (co raczej w końcu nastąpi), to przy nowej wersji biblioteki i zmianie bebechów mój kod przynajmniej wywali się na etapie kompilacji, a nie w czasie wykonania, bo refleksja nie znalazła pól. No ale to korporacyjny kod, w nim różnymi hakami trzeba sobie radzić.

Dygresja: kiedyś mieliśmy problem z Microsoft Workflow Foundation, gdzieś w jakiejś klasie było prywatne pole typu Dictionary (konkretna implementacja, a nie interfejs). Okazało się, że WF źle synchronizował dostęp do tego pola i mieliśmy przez to sporo problemów. Niestety nie dało się tego naprawić przez podmianę słownika na synchronizowany, bo pole miało zły typ, żadna refleksja tu nie pomogła, a MS już nie rozwijał tego produktu i nie było szans na normalną poprawkę. Ostatecznie musieliśmy zakładać blokady kilka poziomów wyżej, dzięki czemu kod zaczął działać poprawnie, ale wydajność bardzo spadła.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 13 godzin
  • Lokalizacja:Wrocław
0
jarekr000000 napisał(a):

Taka prostacka reguła mówi, że jeśli zewnętrzna biblioteka wymaga abyś używał dziedziczenia po zdefiniowanych w niej klasach - to nie jest już to bilblioteka, ale framework.

Owszem, we frameworkach to konieczność, żeby w ogóle cokolwiek w oparciu o framework zrobić. Tylko tu chodzi o coś innego - potrzebę użycia kawałka zewnętrznego kodu w inny sposób niż zaimplementowali jego twórcy. Niezły przykład tego podał @Afish wyżej.

I dlatego też frameworki są do d...y, a bilblioteki rządzą :-)

Frameworki trzeba umieć pisać. Framework powinien być nakładką dodającą funkcje, a nie fasadą ukrywającą wszystko to, z czego sam korzysta.

edytowany 1x, ostatnio: somekind
V-2
  • Rejestracja:prawie 8 lat
  • Ostatnio:9 miesięcy
  • Postów:671
2
Afish napisał(a):

Osobiście bardzo lubię podejście z Pythona, gdzie nie ma prywatnych pól, a jedynie oznacza się je przez nazewnictwo. Prywatne pola i klasy final fajnie brzmią na kartce, ale w rzeczywistości i tak kończy się to hakami przy użyciu refleksji.

Ja nie wiem, co wy robicie, że to dla was chleb powszedni, aby rozłamywać cudze abstrakcje refleksją. Już jakiś czas w tym zawodzie robię - i nie na kartce - a w zasadzie nie jestem w stanie sobie przypomnieć takiego przypadku, żebym stanął przed taką koniecznością.

Oczywiście nie twierdzę, że nie mogą się zdarzyć, jak ten opisany przez ciebie problem z WF - w porządku. (Zaryzykowałbym stwierdzenie, że jest to w zasadzie zasłużona boska kara za używanie Workflow Foundation, Sharepointów itp. grzesznych molochów).

Natomiast tak czy siak są to raczej sytuacje skrajne i wysnuwać z nich jakieś ogólne architektoniczne konkluzje, że najlepiej robić wszystko protected - a może i na zaś public - to podobna paranoja, jak u mojej starej ciotki, co wszędzie nosi chlebak z latarką kieszonkową i zapasem leków na wypadek ataku terrorystycznego. (Tak, wiem, że pewnego strasznego dnia wyjdzie, że to ona miała rację).


Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem, ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia. W drugiej firmie której już pracuję mam palących marihuanę programistów [...] piszą kod "leniwie", często nie wysilając się, rozwlekając ten kod, unikając np. programowania funkcyjnego (mówię tutaj o lambdach w javie).
edytowany 2x, ostatnio: V-2
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:12 dni
0
V-2 napisał(a):

Już jakiś czas w tym zawodzie robię - i nie na kartce - a w zasadzie nie jestem w stanie sobie przypomnieć takiego przypadku, żebym stanął przed taką koniecznością.

Życie. Jeden przez całą karierę ani razu nie zrobi zrzutu pamięci, a inny codziennie będzie tak musiał debugować, jeden użyje refleksji raz do roku, a inny będzie musiał haczyć na porządku dziennym.

V-2
  • Rejestracja:prawie 8 lat
  • Ostatnio:9 miesięcy
  • Postów:671
0
Afish napisał(a):
V-2 napisał(a):

Już jakiś czas w tym zawodzie robię - i nie na kartce - a w zasadzie nie jestem w stanie sobie przypomnieć takiego przypadku, żebym stanął przed taką koniecznością.

Życie. Jeden przez całą karierę ani razu nie zrobi zrzutu pamięci, a inny codziennie będzie tak musiał debugować, jeden użyje refleksji raz do roku, a inny będzie musiał haczyć na porządku dziennym.

Oczywiście. To zależy od wybranej technologii, umiejętności, charakteru i jakości projektu itd. niezliczonych czynników. No i właśnie dlatego nie powinieneś z miejsca zakładać, że punkty widzenia niepotwierdzone przez twoje prywatne doświadczenie "fajnie brzmią na kartce" - czyli że mają zastosowanie już wyłącznie w teorii. Bo mogą świetnie sprawdzać się w praktyce całkiem sporej grupy ludzi; może nawet większej liczebnie.


Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem, ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia. W drugiej firmie której już pracuję mam palących marihuanę programistów [...] piszą kod "leniwie", często nie wysilając się, rozwlekając ten kod, unikając np. programowania funkcyjnego (mówię tutaj o lambdach w javie).
edytowany 2x, ostatnio: V-2
AF
Wyraziłem swoją opinię, do tego właśnie jest to forum. Jak masz inną, to ja nie mam z tym problemu.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)