Autor Téma: TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm  (Přečteno 1366 krát)

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4341
  • Karma: 38
    • Verze Delphi: XE7 professional

Kód: Delphi [Vybrat]
  1. unit BasalForm;
  2. interface
  3. type
  4.   TBasalForm = class(TForm)
  5.   strict protected
  6.     procedure CreateObjects; virtual;
  7.     procedure CreateSQL; virtual;
  8.     procedure SetForm; virtual;
  9.   public
  10.     constructor CreateForm;
  11.     destructor Destroy; override;
  12.     property pRecord: TList<Pointer> read FpRecord;
  13.   end;
  14. implementation
  15. constructor TBasalForm.CreateForm;
  16. begin
  17.   inherited Create(nil);
  18.   SetForm;
  19. end;
  20.  
  21.  
  22. destructor TBasalForm.Destroy;
  23. begin
  24.   if Assigned(oGlobalVar) and (oGlobalVar.ListOfObjects.Count > 0) then
  25.     oGlobalVar.DestroyObjects;
  26.   inherited;
  27. end;
  28.  
  29.  
  30. procedure TBasalForm.CreateObjects;
  31. begin
  32. end;
  33.  
  34.  
  35. procedure TBasalForm.CreateSQL;
  36. begin
  37. end;
  38.  
  39.  
  40. procedure TBasalForm.SetForm;
  41. begin
  42.   CreateSQL;
  43.   CreateObjects;
  44. end;
Všade to funguje (CreateForm, Destroy), len pre hlavný formulár aplikácie nie. Ten vytváram až po spustení aplikácie dynamicky. Netuším prečo a tak to neviem spojazdniť.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4341
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #1 kdy: 25-01-2019, 13:01:02 »
Áno, tvorím ho tak. Takže jedna vec je jasná. Ako dosiahnem, aby sa mi zavolal BasalForm.Create?
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4341
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #2 kdy: 25-01-2019, 13:27:45 »
Ďakujem, už to ide. A ja si pozriem prečo.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2579
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #3 kdy: 25-01-2019, 15:04:51 »
P.S. k vytvoreni metod bez implementace je vhodnejsi pouzit direktivy virtual; abstract; nez jen virtual s prazdnou implementaci. Metody by vzdy nejakou implementaci mit mely; pokud realnou implementaci neobsahuji, mely by alespon vyvolat vyjimku ENotImplemented, pripadne ENotSupportedException.
To je hloupost: pokud pouzivam polymorfismus, tak existuji dva zakladni pripady:
- chci prinutit kazdeho potomka, ze neco musi implementovat, tak pouziju abstract
- chci dat kazdemu potomkovi moznost prekryt implicitni chovani a pak pouziju virtual a v bazalni tride udelam spolecnou implementaci, treba prazdnou by default.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4341
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #4 kdy: 25-01-2019, 15:07:50 »
Práve som napísal odpoveď, ale toto je podstatne lepšie a výstižnejšie.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline pepak

  • Guru
  • *****
  • Příspěvků: 1412
  • Karma: 34
    • Pepak.net
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #5 kdy: 25-01-2019, 16:07:08 »
Excellent
Rated 1 time
S tou prazdnou metodou nesouhlasim. Pokud nema metoda implementaci, mela by byt abstraktni. Pokud i presto chces implementaci deklarovat, mel bys IMHO stejne jako v pripade volani neprekryte abstraktni metody vyvolat vyjimku.
Ty necítíš rozdíl mezi metodou, která nemá implementaci, a metodou, která má implementaci, která nic nedělá? Nebo jsi zastáncem názoru, že metoda TObject.AfterConstruction měla být deklarována jako abstract, protože přece nemá implementaci a každý potomek TObject si ji může snadno naimplementovat podle svých představ?

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4341
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #6 kdy: 25-01-2019, 16:49:23 »
Citace
Pokud i presto chces implementaci deklarovat, mel bys IMHO stejne jako v pripade volani neprekryte abstraktni metody vyvolat vyjimku.
A toto je vec ktorej nerozumiem. Prečo mám obsluhovať nejakú výnimku, keď to nie je chyba, ale zámer (prázdna rutina)? Môžeš mi to vysvetliť? A ani si neviem predstaviť ako by taká obsluha výnimky mala vyzerať.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2579
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #7 kdy: 25-01-2019, 17:40:05 »
TObject.AfterConstruction měla být deklarována jako abstract, protože přece nemá implementaci a každý potomek TObject si ji může snadno naimplementovat podle svých představ?
Lepsi priklad pro Delphistu asi neexistuje.

Offline pepak

  • Guru
  • *****
  • Příspěvků: 1412
  • Karma: 34
    • Pepak.net
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #8 kdy: 26-01-2019, 05:24:45 »
Jiste. Jen si stojim za tim, ze by takova metoda mela zajistit vyvolani udalosti nez nedelat vubec nic.
A řešit situaci, kdy stejnou "událost" bude chtít víc různých tříd v řetězci potomků, budeme jak? Seznamem zájemců o obsluhu události? Pořadí událostí bude určeno čím? Jak zařídím, aby potomek úplně nahradil událost z předka?

Jako pro mě za mě si tak programuj, ale můj názor je, že tvoje poněkud fundamentalistické lpění na událostech všude je pomalé, paměťově neefektivní, neohrabané a nedokáže řešit všechny situace, které mohou nastat. Neříkám, že nemáme nikdy používat události - někdy jsou užitečné, tak je použijme, ale podle mě je dobré mít na výběr. Tak, jak to je ve VCL - podle situace se rozhodnu, jestli chci dát událost do OnShow, nebo jestli overridnu DoShow.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2579
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #9 kdy: 26-01-2019, 08:23:18 »
Jiste. Jen si stojim za tim, ze by takova metoda mela zajistit vyvolani udalosti nez nedelat vubec nic.
Mam dojem, ze sis zamenil doporuceni Composition over Inheritance za Composition instead of Inheritance...

Citace
abych nechal metodu prazdnou a z potomka volal inherited s tim, ze se nic nestane...
No to je to zakladni pomyleni dane tim absolutnim nahrazenim dedicnosti kompozici: tam skutecne kazdy musi implementovat metodu rozhrani... Ale pokud bazalni trida implementuje implicitni vlastnosti, tak vsechny odvozene tridy, pokud nepotrebuji menit implicitni vlastnosti, metodu vubec nekrekryvaji a tudiz ani nevolaji zadne inherited...

Jak kompozice, tak dedicnost maji svoje klady a zapory s tim, ze cim blize je vystavovane rozhrani blize aplikacni logice, tim mensi pocet metod zpravidla vystasvuje a tim vetsi vahu bude mit kompozice/delegovani pred dedicnosti. Ale pokud vlastnostni je hodne a odchylek od implicitniho chovani je malo, tak je nesmysl je delegovat, protoze to znamena obrovske mnozstvi zbytecne prace.

Vyborny priklad je to TObject.AfterContruction. Kdyby z toho udelali delegata, jaky overhead u kazde instance TObject by zbytecne zavedli ev. kdyby raisnuli exception (a tim vlastne simulovali to abstract), aby to nebylo prazdne, tak by to kazdy potomek TObject  musel prekryvat prazdnou metodou... To by byl blazinec k nepouziti.



Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2579
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #10 kdy: 26-01-2019, 09:52:56 »
Jiste, spousta lidi si tu rekne, co zase ten delfin plodi za nesmysly, ale to jsem zazil.
Tak ja popisu, co jsem zazil s tupe aplikovanou kompozici, kterou mel na svedomi taky mlady programator - mozna, ze takove ptakoviny skutecne nekde uci - budu se muset preptat  :)

- dostal na hrb soft pro pomerne slozite stroje, kde jeho customizaci resil interface
- na zacatku mel par zakazniku a par vlastnosti
- ale casem se mu pocet customizaci rozrostl na 100+ a pocet vlastnosti na rozhrani na stovky
- novou customizaci vytvarel Copy&Paste z nejake nejpodobnejsi
- novou vlastnost pridaval zpetne do 100+ implementaci intreface s tim, ze vsude byla 'prazdna' nebo implicitni
  krome toho jednoho prave pridaneho zakaznika...
- kdyz chtel nejakou vlastnost zmenit, musel prolezt 100+ interface...

Vyhodu to melo jedinou, ze kdyz nekde neco posr*l, tak to posr*l jen pro tu danou customaci, coz byla zrejme jeho primarni motivace k takovemu masochismu.

No a pak prisel pozadavek zmenit kompletne vsude ksicht podle navrhu graficky vcetne vzhledu gridu apod., coz mj. znamenalo rozsirit
pocet vlastnosti na rozhrani, protoze 2 zakaznici chteli treba vlastni font u konkretniho textu, vsem ostatnim 100+ to bylo jedno
- samozrejme, ze prvnim krokem byl refactoring a vytvoreni spolecnehop rozhrani a jeho implementace
- druhym krokem rozsireni spolecneho rozhrani o nove vlastnosti
- tretim krokem bylo odvozeni rozhrani od toho spolecneho a vyhazeni vsech metod z rozhrani tak, aby implementovala jen to, co bylo pro danou customizaci

A bylo po onanyji a stal se z toho udrzovatelny soft  ;D

« Poslední změna: 26-01-2019, 09:55:21 od pf1957 »

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 815
  • Karma: 59
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #11 kdy: 27-01-2019, 16:25:10 »
Já mám ještě dvě hezké:

Kód: Delphi [Vybrat]
  1. constructor TObject.Create;
  2. begin
  3. end;
  4.  
  5. destructor TObject.Destroy;
  6. begin
  7. end;
Embarcadero Technology Partner

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 4341
  • Karma: 38
    • Verze Delphi: XE7 professional
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #12 kdy: 28-01-2019, 10:13:55 »
Lebo ju občas budem potrebovať a nechcem stratiť možnosť vždy použiť inherited. Kvôli automatizácii spúšťania rutín.
Delphi XE7, FireBird
Expert na kladenie nejasne formulovaných otázok.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2579
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:TfrmFormMain = class(TBasalForm) -> nezbehnú udalosti v TBasalForm
« Odpověď #13 kdy: 28-01-2019, 12:48:37 »
Dobra, jen bych prosil vysveteleni, proc bych mel pro vlastni tridu deklarovat metodu (tedy typu procedure, constructor a destructor), jenz bude prazdna?
To je furt dokola: proste pri analyze a navrhu rozhrani vypadne, ze pro nektere tridy potrebujes nejakou operaci, ktera je vazana na nejakou logiku spolecnou vsem tem tridam, pricemz pocet tech trid neni dopredu znamy a neni konecny. Samozrejme bys to mohl matlat kondicionalem v run-time a operaci volat jen v pozadovanych pripadech. Ale OOP nam nabizi polymorfismus, ktery umoznuje s ruznymi objekty 'anonymne' manipulovat pres jejich spolecne rozhrani.

A to rozhrani muzes vytvorit:
- dedicnosti vystavenim rozhrani spolecne tridy a jeho dedenim/prekryvanim
- kompozici nadefinovanim extra rozhrani a jeho implementaci v kazde instanci
- kombinaci obeho.

Takze je otazka, pro co se rozhodnes:
- u dedicnosti v bazalni tride implementujes prevazujici stav tj. treba NIC
- u kompozice by jsi stav musel explicitne implementovat u kazde implementace rozhrani. Takze tam ti NIC tj. prazdna metoda nevadi  :o ?

BTW, nevim, proc se ti do hlavy zakousla zrovna prazdna procedure, protoze to je jen metoda implementujici nejake implicitni chovani a je uplne jedno, jestli je void nebo ne - podle toho co pises, tak ti zrejme function nevadi  :o

O konstruktorech/destruktorech nechci diskutovat, protoze jejich vlastnosti maji v ruznych jazykach ruzne vlastnosti a nema to tudiz obecnou platnost.