Veoma interesantna tema :)
Citat:
Milan Milosevic: Jednostavno u nekim zelim u nekim ne. Unapred ne mogu znati kad ce sta da mi treba iz osnovne klase. Meni je bitno da ona radi zasta je namenjena.
Mislim da je u ove dve recenice sazet tvoj problem, a cini mi se da je to neispravno razmisljanje / postavljanje stvari.
Klasa roditelj ne bi ni trebalo da brine (zna) sta ce da rade klase potomci, a tu spada i specificna implementacija za svakog (novog i moguceg) potomka. Klasa roditelj treba da pruzi zajednicki okvir za svoje potomke (koji je uvek isti, garantovan interfejsom klase), a na njima je kako ce se oni dalje ponasati (u kom smeru ce se siriti njihova funkcionalnost, ili kako ce oni vec menjati funkcionalnost klase roditelja).
Slozio bih se sa onim sto ti je
Burgos rekao - za primer koji si naveo, dizajn deluje pogresno. Sustina nasledjivanja je omogucavanje razlicitih nivoa apstrakcije odredjenog problema, gde se polazi od viseg nivoa apstrakcije u klasi roditelja (generalizovana funkcionalnost) i dalje specijalizuje kroz klase naslednike (specificne funkcionalnosti).
Ako bi se dozvolilo da naslednici proizvoljno izbacuju funckionalnost roditelja, cela prica bi izgubila smisao i vise niko ziv ne bi znao sta koja klasa moze imati/raditi i odakle je to nasledila. Kao sto je
Burgos vec primetio, polimorfizam ne bi postojao jer vise niko ne bi mogao da garantuje da naslednici sadrze sve elemente roditelja. Ono sto si jednom "obecao" proglasivsi ga npr. javnim, ne mozes vise vratiti da bude privatno, nema tu uzimala-davala :) Mozes dati samo vise (protected proglasiti public), nikad manje.
Dalje, cak i da je moguce, ovo bi samo omogucilo jos veci haos u dizajnu klasa. Zamislimo sledeci primer:
Code:
TSuperKlasa = class
Kljun: TKljun;
Krila: TKrila;
Auspuh: TAuspuh;
Sediste: TSediste;
end;
TPtica = class(TSuperKlasa)
public
Kljun: TKljun;
Krila: TKrila;
end;
TAuto = class(TSuperKlasa)
public
Auspuh: TAuspuh;
Sediste: TSediste;
end;
Uz pretpostavku da osobine koje nismo proglasili javnim u potomcima vise ne postoje, ovakvo mesanje baba i zaba bi na duze staze bila ogromna glavobolja. Ogranicenja koja postoje su (obicno ;)) tu s razlogom, nekada se zbog njih mora malo vise razmisljati na pocetku, ali je zato kasnije mnogo lakse - u suprotnom bi na pocetku pisali sta nam prvo padne na pamet, a kasnije bi se hvatali za glavu sta sad da radimo. Lako je kad je projekat mali, ali kako raste tako i najmanje omaske u dizajnu postaju itekako uocljive i problematicne, pa je zato vrlo vazno od pocetka raditi sto ispravnije.
Medjutim, ako sam te dobro razumeo, tebi je zapravo problem kako da sakrijes neke stvari iz npr. menija koji daje Code Completion (jer je inace nemoguce da sprecis korisnika da koristi ono sto mu po pravilima nasledjivanja sleduje, a kojih se Delphi drzi). E sad, ako mozemo da se slozimo da je ovo suprotno ideji nasledjivanja, a ti sa druge strane ne zelis da menjas dizajn klasa roditelja, mogu da ti predlozim da umesto nasledjivanja koristis kompoziciju, primer:
Code:
TPtica = class
private
SuperKlasa: TSuperKlasa;
function GetKljun(): TKljun;
public
property Kljun: TKljun read GetKljun;
end;
implementation
function TPtica.GetKljun(): TKljun;
begin
Result := Self.SuperKlasa.Kljun;
end;
Na ovaj nacin mozes iz klase TSuperKlasa koristiti (prikazati) samo onu funkcionalnost koja ti zapravo treba u novoj klasi TPtica, pritom nikoga ne dovodeci u zabludu da li je TPtica naslednik TSuperKlasa ili ne, sakrivanjem funkcionalnosti koja ti nije potrebna. TPtica nije naslednik (potomak) TSuperKlasa, ali ce njeni naslednici moci da koriste funkcionalnost iz TSuperKlasa koju im TPtica omoguci. Naravno, ne treba posebno napominjati da je duznost i obaveza klase TPtica da se postara da ta funkcionalnost iz TSuperKlasa bude ispravna (obzirom da se ne koristi cela TSuperKlasa).