Autor Téma: Vytvorenie triedy a správny spôsob jej "spustenia"  (Přečteno 1556 krát)

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5307
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Vytváram si triedy pre tlač zostáv a súčasne pozerám do múdrej knihy. Vďaka tomu mám
Kód: Delphi [Vybrat]
  1.   TAbstractPrintFR = class  // Nie je to singleton.
  2.  
  3.     public constructor Create(ATypeReport: TTypeReport); virtual; abstract;
  4.   end;
  5.  
  6.   TBasePrintFR = class(TAbstractPrintFR)
  7.   ...
  8.  
Predpokladám takúto procedúru:
Kód: Delphi [Vybrat]
  1.    procedure PrintReport(ATypeReport: TTypeReport);
  2.    var
  3.      oBasePrintFR: TBasePrintFR;
  4.    begin
  5.      oBasePrintFR := TBasePrintFR.Create(ATypeReport);
  6.      FreeAndNil(oBasePrintFR);
  7.    end;
  8.  
Otázka znie ako to mám spustiť.
  1) procedúru vytvorím v GlobalVar ako súčasť triedy
Kód: Delphi [Vybrat]
  1.    oGlobalVar.PrintReport(MyTypeReport);  // Ukryl som ju.
  2.  
  2) alebo v časti interface niektorej jednotky. Najväčším kandidátom je GlobalVar.
Kód: Delphi [Vybrat]
  1.    PrintReport(MyTypeReport);
  2.  
  3) alebo sa to rieši ináč.

Ďakujem.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Online pf1957

  • Padawan
  • ******
  • Příspěvků: 2930
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #1 kdy: 06-09-2017, 09:39:25 »
Ja bych to resil asi factory (sorry za formu, ale uz mi ty Delphi konvence nejdou):
Kód: Delphi [Vybrat]
  1. var printer: TBasePrintFR;
  2. try
  3.   printer := ReportPrinterFactory.GetPrinter(AReportType);
  4.   try
  5.     printer.Print(...);
  6.   finally
  7.     printer.Free;
  8.   end;
  9. except
  10.   ...
  11. end;
  12.  
  13.  

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5307
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #2 kdy: 06-09-2017, 10:12:15 »
To vyzerá celkom zaujímavo. Veľmi to zvážim.
Len ten ReportPrinterFactory budem musieť mať ako globálnu premennú a singelton.
Citace
sorry za formu, ale uz mi ty Delphi konvence nejdou
Na tom nezáleží. Dôležitá je myšlienka ktorú z toho vyčítam.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Online pf1957

  • Padawan
  • ******
  • Příspěvků: 2930
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #3 kdy: 06-09-2017, 11:26:38 »
Len ten ReportPrinterFactory budem musieť mať ako globálnu premennú a singelton.
Singlton ano, globalni promennou ne. Normalne se to dela tak, ze se konstruktor udela private, aby se znemoznilo delat instance primo a pak se udela property Instance, ktera si zajistit autimaticky vytvoreni prave jedne instance, takze pak pouziti je
Kód: Delphi [Vybrat]
  1.   printer = TReportPrinterFactory.Instance.GetPrinter(AReportType);
  2.  

Takze v Delphi snad takto:
Kód: Delphi [Vybrat]
  1.   TReportPrinterFactory = class
  2.   strict private
  3.     class var FInstance: TReportPrinterFactory;
  4.   strict private
  5.     constructor Create();
  6.     class function __GetInstance: TReportPrinterFactory; static;
  7.   public
  8.     function GetPrinter(AReportType:TReportType): TBaseReportPrinter;
  9.   public
  10.     class property Instance: TReportPrinterFactory read __GetInstance;
  11.   end;
  12.  

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1516
  • Karma: 37
    • Pepak.net
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #4 kdy: 07-09-2017, 19:11:02 »
Jsi si jistý tím privátním konstruktorem? Každá třída v Delphi dědí z TObject, který má public constructor, takže použitím privátního konstruktoru akorát programátora směřuješ k tomu, aby při intuitivním použití, na které je zvyklý ze všech jiných tříd, použil konstruktor nesprávný...

Online pf1957

  • Padawan
  • ******
  • Příspěvků: 2930
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #5 kdy: 07-09-2017, 19:34:34 »
Jsi si jistý tím privátním konstruktorem? Každá třída v Delphi dědí z TObject, který má public constructor, takže použitím privátního konstruktoru akorát programátora směřuješ k tomu, aby při intuitivním použití, na které je zvyklý ze všech jiných tříd, použil konstruktor nesprávný...
Jisty si nejsem, protoze uz v Delphi radu let nedelam a je mozne, ze v Delphi napsat cisty singleton, u ktereho by programator nemohl za zadnych okolnosti vytvorit vice instanci, proste nejde.

96902

  • Host
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #6 kdy: 07-09-2017, 19:50:32 »
je mozne, ze v Delphi napsat cisty singleton, u ktereho by programator nemohl za zadnych okolnosti vytvorit vice instanci, proste nejde.

Ciste ne :)
Jine reseni v tom vlakne vracejici objekt riskuje ze ten objekt uvolnis (tohle nedoporucuju):

Kód: Delphi [Vybrat]
  1. function Singleton: TObject;
  2.  
  3. implementation
  4.  
  5. var
  6.   Instance: TObject;
  7.  
  8. function Singleton: TObject;
  9. begin
  10.   if not Assigned(Instance) then
  11.     Instance := TObject.Create;
  12.   Result := Instance;
  13. end;
  14.  
  15. ...
  16.   Singleton.Free; // ted zustane v Instance rozbity Assigned objekt
« Poslední změna: 07-09-2017, 19:59:28 od 96902 »

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5307
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #7 kdy: 07-09-2017, 21:31:37 »
Ale videl som niekoľko prípadov s tým Free. Jaj, nie free ale Instance := nil.
Pravdu povediac, ten privátny konštruktér ma riadne mätie. Na jednej strane som čítal, že nie je potrebný a potom sa tam objaví.
Vo svojom riešení som ho vyhodil. V diskusii to autorovi napadli a tak to dodatočne škrtol. Mám to po dvojdňovom boji takto:
Kód: Delphi [Vybrat]
  1.   TPrintFRFactory = class  // Je to singleton.
  2.   strict private
  3.     class var FInstance: TPrintFRFactory;
  4. //    constructor Create;
  5.     {Client code should use this function ("_GetInstance"), instead of the
  6.      "constructor" to create (or access) a singelton instance}
  7.     class function _GetInstance: TPrintFRFactory; static;
  8.   public
  9.     destructor Destroy; override;
  10.     class function New(ClassOfPrintFRBase: TPrintFRBaseClass): TPrintFRBase;
  11.     class property Instance: TPrintFRFactory read _GetInstance;
  12.   end;
  13.  
Ale nerozumiem načo tam je to property Instance. Ja to osobne v tomto prípade nepotrebujem. A prečo tomu nerozumiem. Inštancia triedy sa neukladá do globálne premennej. Čo osobne vítam. Tak ako sa k nej dostanem? To by som rád vedel.

PS: Majte na mysli moju takzvanú angličtinu.
« Poslední změna: 07-09-2017, 21:36:17 od Stanislav Hruška »
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

96906

  • Host
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #8 kdy: 07-09-2017, 22:29:19 »
Ale nerozumiem načo tam je to property Instance. Ja to osobne v tomto prípade nepotrebujem. A prečo tomu nerozumiem. Inštancia triedy sa neukladá do globálne premennej. Čo osobne vítam. Tak ako sa k nej dostanem? To by som rád vedel.

Prave ze zadnou vnejsi instanci nema. Ma class var do ktere se jedina instance ulozi po prvnim volani metody _GetInstance. Ty volas jen tohle (a tim prvotnim pristupem k property Instance se vytvori interne schovana instance):

Kód: Delphi [Vybrat]
  1. var
  2.   Report: TPrintFRBase;
  3. begin
  4.   Report := TPrintFRFactory.Instance.New(TMyReport);
  5. end;

U tohoto bych se ale spis nez vytvoreni instance obaval jejiho zniceni:

Kód: Delphi [Vybrat]
  1. TPrintFRFactory.Instance.Free;
« Poslední změna: 07-09-2017, 22:37:13 od 96906 »

Online pf1957

  • Padawan
  • ******
  • Příspěvků: 2930
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #9 kdy: 07-09-2017, 22:41:43 »
Kód: Delphi [Vybrat]
  1. var
  2.   Report: TPrintFRBase;
  3. begin
  4.   Report := TPrintFRFactory.Instance.New(TMyReport);
  5. end;
Jenomze on New() nema jako metodu instance, ale metodu tridy, takze referovat ji pres Instance by nemelo jit ani prelozit (co na to Delphi nevim)... Pak samozrejme property Instance na nic nepotrebuje, kdyz udela tovarnu celou statickou.

96908

  • Host
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #10 kdy: 08-09-2017, 00:38:16 »
[quote  link=topic=15804.msg96906#msg96906 date=1504816159]
Kód: Delphi [Vybrat]
  1. var
  2.   Report: TPrintFRBase;
  3. begin
  4.   Report := TPrintFRFa ctory.Instance.New(TMyReport);
  5. end;
Jenomze on New() nema jako metodu instance, ale metodu tridy, takze referovat ji pres Instance by nemelo jit ani prelozit (co na to Delphi nevim)... Pak samozrejme property Instance na nic nepotrebuje, kdyz udela tovarnu celou statickou.
[/quote]

Moje chyba, omlouvam se. Napsal jsem nesmysl. Jinak, pokud se trida vytvori cela staticka pak neni treba tridy. Uplnym zrusenim schopnosti tvorit instance (i za cenu toho ze budou ulozeny v class var) pak nepujde primo o singleton.

Kdyz jsme u toho odchylovani od definice; pokud by nevadilo ukladani reference na record ktery ma jen staticke metody a nic vic, pak by slo napsat i tohle (ma to vyhodu v tom, ze Code Completion nenabidne nic vic nez tu jedinou metodu a neni treba se trapit se schovavanim konstruktoru apod.):

Kód: Delphi [Vybrat]
  1. unit UnitFactory;
  2.  
  3. interface
  4.  
  5. uses
  6.   Dialogs;
  7.  
  8. type
  9.   TProduct = class
  10.   public
  11.     procedure DoSomething;
  12.   end;
  13.   TProductClass = class of TProduct;
  14.  
  15.   TFactory = record
  16.   public
  17.     class function New(ClassType: TProductClass): TProduct; static;
  18.   end;
  19.  
  20. implementation
  21.  
  22. { TFactory }
  23.  
  24. class function TFactory.New(ClassType: TProductClass): TProduct;
  25. begin
  26.   Result := ClassType.Create;
  27. end;
  28.  
  29. { TProduct }
  30.  
  31. procedure TProduct.DoSomething;
  32. begin
  33.   ShowMessage('TProduct.DoSomething');
  34. end;
  35.  
  36. end.

Pak jinde v kodu:

Kód: Delphi [Vybrat]
  1. var
  2.   Product: TProduct;
  3. begin
  4.   Product := TFactory.New(TProduct);
  5.   Product.DoSomething;
  6. end;

Bohuzel referenci na takovy record si muzu ulozit, coz se jeste vice odchyluje od definice singletonu. Cili tohle by singleton nemel umoznit, s recordem to bohuzel jde:

Kód: Delphi [Vybrat]
  1. var
  2.   MyFactory: TFactory;
  3.   MyProduct: TProduct;
  4. begin
  5.   MyProduct := MyFactory.New(TProduct);
  6.   MyProduct.DoSomething;
  7. end;

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5307
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #11 kdy: 08-09-2017, 09:14:00 »
Mám to riešené takto:
Kód: Delphi [Vybrat]
  1.   TPrintAbstract = class
  2.    public constructor Create(); virtual; abstract;
  3.  
  4.   TPrintFRBase = class(TPrintAbstract)
  5.  
  6.   TPrintFRBaseClass = class of TPrintFRBase;
  7.  
  8.   TPrintFRFactory = class  // Je to singleton.
  9.   strict private
  10.     class var FInstance: TPrintFRFactory;
  11.   public
  12.     destructor Destroy; override;
  13.     class function New(ClassOfPrintFRBase: TPrintFRBaseClass): TPrintFRBase;
  14.   end;
  15.  
Použitie
Kód: Delphi [Vybrat]
  1.   TPrintFRFactory.New(TPrintBilling);  // Tu sa mi automaticky zobrazí zostava.
  2.   FreeAndNil(PrintFRBase);
  3.  
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5307
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #12 kdy: 28-06-2018, 08:50:14 »
Vraciam sa späť k tejto téme. Nechápem tu nejaké veci a tak mám v aplikácii poriadny blud.
Citace
Prave ze zadnou vnejsi instanci nema. Ma class var do ktere se jedina instance ulozi po prvnim volani metody _GetInstance. Ty volas jen tohle (a tim prvotnim pristupem k property Instance se vytvori interne schovana instance)
Tu je pre mňa kameň úrazu. Bavili sme sa o tom, že to bude bez globálnej premennej. Ja som to pochopil tak, že nikde nemám mať
Kód: Delphi [Vybrat]
  1. oPrintFRFactory: TPrintFRFactory
Ale ako sa potom dostanem k samotnej inštancii, aby som mohol použiť metódu _GetInstance? ??? ??? ???
Alebo mám oPrintFRFactory: TPrintFRFactory mať v triede, ktorá to bude používať?
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

100340

  • Host
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #13 kdy: 28-06-2018, 09:01:31 »
Ale ako sa potom dostanem k samotnej inštancii, aby som mohol použiť metódu _GetInstance? ??? ??? ???
Alebo mám oPrintFRFactory: TPrintFRFactory mať v triede, ktorá to bude používať?

Ano, bez globalni promenne. Pristupem ke class property Instance se zavola getter _GetInstance ktery vytvori a interne ulozi do class var FInstance (nebo z ni vrati uz existujici) instanci objektu tovarny.

A trida objektu (produktu tovarny) nema o tovarne vedet vubec nic.
« Poslední změna: 28-06-2018, 09:04:49 od 100340 »

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5307
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Vytvorenie triedy a správny spôsob jej "spustenia"
« Odpověď #14 kdy: 28-06-2018, 09:11:46 »
Citace
Pristupem ke class property Instance
Ale ja stále nechápem, nerozumiem, neviem ako sa k tomu dostanem. Čo kde je, keď si inštanciu nikde neukladám a premenná FInstance je strict private. Výnimočne prosím o názornú ukážku použitia.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.