Jump to content

iiid354

Members
  • Content Count

    5
  • Joined

  • Last visited

Posts posted by iiid354


  1. I've started to try to implement it but it doesn't really work even with what you guys wrote, thus attached my example code I've so far:

     

    humas.pas

    unit humans;
    
    interface
    
    type
      { common functions }
      ICommonFunc = interface
      ['{e1f156de-2e6e-4b93-a3b2-c723e73e75da}']
        function Work(const AMessage: String): boolean;
        function AsText(): String;
        function GetStillInCompany(): Boolean;
        property IsStillInCompany: Boolean read GetStillInCompany;
      end;
    
      { common Human }
      IHumanInfo = interface
      ['{6a4f763e-5365-4012-bd7b-520dbe8bfeb8}']
        function GetContractStart(): Integer;
        property StartOfContract: Integer read GetContractStart;
      end;
    
      THumanInfo = class(TInterfacedObject, IHumanInfo)
      private
        FFirstname: String;
        FLastname: String;
        FContractStart: Integer;
      public
        constructor Create(const AFirstname, ALastname: String);
    
        function GetContractStart(): Integer;
      end;
    
      { Manager }
      IManagerInfo = interface
      ['{c2ef4c56-60ac-4e5b-a3a6-674c4ff94b34}']
        function GetAmountSubworkers(): Integer;
        property AmountSubWorkers: Integer read GetAmountSubworkers;
      end;
    
      TManagerInfo = class(TInterfacedObject, IManagerInfo)
      private
        FSubworkers: Integer;
      public
        constructor Create(const ASubWorkers: Integer);
    
        function GetAmountSubworkers(): Integer;
      end;
    
      { Sales }
      ISalesInfo = interface
      ['{29ad75e3-6bae-4221-9e98-5979dcaf347f}']
        function GetSoldCars(): Integer;
        function GetSoldDrinks(): Integer;
        property SoldCars: Integer read GetSoldCars;
        property SoldDrinks: Integer read GetSoldDrinks;
      end;
    
      TSalesInfo = class(TInterfacedObject, ISalesInfo)
      private
        FSoldCars: Integer;
        FSoldDrinks: Integer;
      public
        constructor Create(const ASoldCars, ASoldDrinks: Integer);
    
        function GetSoldCars(): Integer;
        function GetSoldDrinks(): Integer;
      end;
    
      { real classes with all information needed }
      THuman = class(TInterfacedObject, ICommonFunc, IHumanInfo)
      private
        FHumanInfo: IHumanInfo;
        FStillInCompany: Boolean;
      public
        constructor Create(const AFirstname, ALastname: String);
        destructor Destroy; override;
    
        function Work(const AMessage: String): boolean;
        function AsText(): String;
        function GetStillInCompany(): Boolean;
    
        property HumanInfo: IHumanInfo read FHumanInfo implements IHumanInfo;
      end;
    
      TManager = class(TInterfacedObject, ICommonFunc, IHumanInfo, IManagerInfo)
      private
        FHumanInfo: IHumanInfo;
        FManagerInfo: IManagerInfo;
        FStillInCompany: Boolean;
      public
        constructor Create(const AFirstname, ALastname: String; const ASubWorkers: Integer);
        destructor Destroy; override;
    
        function Work(const AMessage: String): boolean;
        function AsText(): String;
        function GetStillInCompany(): Boolean;
    
        property HumanInfo: IHumanInfo read FHumanInfo implements IHumanInfo;
        property ManagerInfo: IManagerInfo read FManagerInfo implements IManagerInfo;
      end;
    
      TSales = class(TInterfacedObject, ICommonFunc, IHumanInfo, ISalesInfo)
      private
        FHumanInfo: IHumanInfo;
        FSalesInfo: ISalesInfo;
        FStillInCompany: Boolean;
      public
        constructor Create(const AFirstname, ALastname: String; const ASoldCars, ASoldDrinks: Integer);
        destructor Destroy; override;
    
        function Work(const AMessage: String): boolean;
        function AsText(): String;
        function GetStillInCompany(): Boolean;
    
        property HumanInfo: IHumanInfo read FHumanInfo implements IHumanInfo;
        property SalesInfo: ISalesInfo read FSalesInfo implements ISalesInfo;
      end;
    
      TSalesManager = class(TInterfacedObject, ICommonFunc, IHumanInfo, ISalesInfo, IManagerInfo)
      private
        FHumanInfo: IHumanInfo;
        FSalesInfo: ISalesInfo;
        FManagerInfo: IManagerInfo;
        FStillInCompany: Boolean;
      public
        constructor Create(const AFirstname, ALastname: String);
        destructor Destroy; override;
    
        function Work(const AMessage: String): boolean;
        function AsText(): String;
        function GetStillInCompany(): Boolean;
    
        property HumanInfo: IHumanInfo read FHumanInfo implements IHumanInfo;
        property SalesInfo: ISalesInfo read FSalesInfo implements ISalesInfo;
        property ManagerInfo: IManagerInfo read FManagerInfo implements IManagerInfo;
      end;
    
    implementation
    
    uses
      SysUtils;
    
    constructor THumanInfo.Create(const AFirstname, ALastname: String);
    begin
      writeln('THumanInfo.Create');
      FFirstname := AFirstname;
      FLastname := ALastname;
      FContractStart := 1990;
    end;
    
    function THumanInfo.GetContractStart: Integer;
    begin
      writeln('GetContractStart');
      Result := FContractStart;
    end;
    
    constructor TManagerInfo.Create(const ASubWorkers: Integer);
    begin
      writeln('TManagerInfo.Create');
      FSubworkers := ASubWorkers;
    end;
    
    function TManagerInfo.GetAmountSubworkers: Integer;
    begin
      writeln('GetAmountSubworkers');
      Result := FSubworkers;
    end;
    
    constructor TSalesInfo.Create(const ASoldCars, ASoldDrinks: Integer);
    begin
      writeln('TSalesInfo.Create');
      FSoldCars := ASoldCars;
      FSoldDrinks := ASoldDrinks;
    end;
    
    function TSalesInfo.GetSoldCars: Integer;
    begin
      writeln('GetSoldCars');
      Result := FSoldCars;
    end;
    
    function TSalesInfo.GetSoldDrinks: Integer;
    begin
      writeln('GetSoldDrinks');
      Result := FSoldDrinks;
    end;
    
    constructor THuman.Create(const AFirstname, ALastname: String);
    begin
      writeln('THuman.Create');
      FHumanInfo := THumanInfo.Create(AFirstname, ALastname);
      FStillInCompany := True;
    end;
    
    destructor THuman.Destroy;
    begin
      writeln('THuman.Destroy');
    //  FHumanInfo.Free;
      inherited;
    end;
    
    function THuman.Work(const AMessage: String): boolean;
    begin
      Result := False;
      writeln('THuman.Work');
      writeln('doing my work', AMessage);
      Result := True;
    end;
    
    function THuman.AsText: String;
    begin
      writeln('THuman.AsText');
      Result := 'default';
    end;
    
    function THuman.GetStillInCompany(): Boolean;
    begin
      writeln('THuman.GetStillInCompany');
      Result := FStillInCompany;
    end;
    
    constructor TManager.Create(const AFirstname, ALastname: String; const ASubWorkers: Integer);
    begin
      writeln('TManager.Create');
      FHumanInfo := THumanInfo.Create(AFirstname, ALastname);
      FManagerInfo := TManagerInfo.Create(ASubWorkers);
      FStillInCompany := True;
    end;
    
    destructor TManager.Destroy;
    begin
      writeln('TManager.Destroy');
    //  FHumanInfo.Free;
    //  FManagerInfo.Free;
      inherited;
    end;
    
    function TManager.Work(const AMessage: String): boolean;
    begin
      Result := False;
      writeln('TManager.Work');
      writeln('just telling others what to do', AMessage);
      Result := True;
    end;
    
    function TManager.AsText: String;
    begin
      writeln('TManager.AsText');
      Result := 'boss';
    end;
    
    function TManager.GetStillInCompany(): Boolean;
    begin
      writeln('TManager.GetStillInCompany');
      Result := FStillInCompany;
    end;
    
    constructor TSales.Create(const AFirstname, ALastname: String; const ASoldCars, ASoldDrinks: Integer);
    begin
      writeln('TSales.Create');
      FHumanInfo := THumanInfo.Create(AFirstname, ALastname);
      FSalesInfo := TSalesInfo.Create(ASoldCars, ASoldDrinks);
      FStillInCompany := True;
    end;
    
    destructor TSales.Destroy;
    begin
      writeln('TSales.Destroy');
    //  FHumanInfo.Free;
    //  FSalesInfo.Free;
      inherited;
    end;
    
    function TSales.Work(const AMessage: String): boolean;
    begin
      Result := False;
      writeln('TSales.Work');
      writeln('making money', AMessage);
      Result := True;
    end;
    
    function TSales.AsText: String;
    begin
      writeln('TSales.AsText');
      Result := 'MONEY';
    end;
    
    function TSales.GetStillInCompany(): Boolean;
    begin
      writeln('TSales.GetStillInCompany');
      Result := FStillInCompany;
    end;
    
    constructor TSalesManager.Create(const AFirstname, ALastname: String);
    begin
      writeln('TSalesManager.Create');
      FHumanInfo := THumanInfo.Create(AFirstname, ALastname);
      FSalesInfo := TSalesInfo.Create(0, 5);
      FManagerInfo := TManagerInfo.Create(1);
      FStillInCompany := True;
    end;
    
    destructor TSalesManager.Destroy;
    begin
      writeln('TSalesManager.Destroy');
    //  FHumanInfo.Free;
    //  FSalesInfo.Free;
    //  FManagerInfo.Free;
      inherited;
    end;
    
    function TSalesManager.Work(const AMessage: String): boolean;
    begin
      Result := False;
      writeln('TSalesManager.Work');
      writeln('making money', AMessage);
      Result := True;
    end;
    
    function TSalesManager.AsText: String;
    begin
      writeln('TSalesManager.AsText');
      Result := 'MONEY and BOSS';
    end;
    
    function TSalesManager.GetStillInCompany(): Boolean;
    begin
      writeln('TSalesManager.GetStillInCompany');
      Result := FStillInCompany;
    end;
    
    end.

    show.pas

    unit show;
    
    interface
    
    uses humans;
    
    function ShowInfoText(r: IHumanInfo): String;
    function GetSubWorkers(r: IHumanInfo): Integer;
    function GetSoldDrinks(r: IHumanInfo): Integer;
    
    implementation
    
    uses
      SysUtils;
    
    function ShowInfoText(r: IHumanInfo): String;
    begin
      Result := 'this text should not appear';
      // function is always available
      //Result := IHumanInfo(r).AsText; // => Error: identifier idents no member "AsText"
    end;
    
    function GetSubWorkers(r: IHumanInfo): Integer;
    begin
      Result := -1;
    
      if r is IManagerInfo then
      begin
        Result := IManagerInfo(r).GetAmountSubworkers;
      end;
    end;
    
    function GetSoldDrinks(r: IHumanInfo): Integer;
    begin
      Result := -1;
    
      if r is ISalesInfo then
      begin
        Result := ISalesInfo(r).GetSoldDrinks;
      end;
    end;
    
    end.

    test.lpr

    program test;
    
    {$APPTYPE CONSOLE}
    
    {$IFDEF FPC}
      {$mode Delphi}
    {$ENDIF}
    
    uses SysUtils, Classes, humans, show;
    
    var
      fHuman: IHumanInfo;
      fSales: IHumanInfo;
      fManager: IHumanInfo;
      fSalesManager: IHumanInfo;
    
    procedure ShowInfo(res: IHumanInfo);
    begin
      writeln('  ', ShowInfoText(res));
      writeln('  ', GetSubWorkers(res));
      writeln('  ', GetSoldDrinks(res));
    end;
    
    begin
      writeln('-1-');
      fHuman := THuman.Create('Alberto', 'Galva');
      ShowInfo(fHuman);
    
      writeln('-2-');
      fSales := TSales.Create('Emir', 'Naldo', 10, 27);
      ShowInfo(fSales);
    
      writeln('-3-');
      fManager := TManager.Create('Diana', 'Snicker', 3);
      ShowInfo(fManager);
      //fManager.Work('hello'); // => Error: identifier idents no member "Work"
      ShowInfo(fManager);
    
      writeln('-4-');
      fSalesManager := TSalesManager.Create('Roberto', 'Miaz');
      ShowInfo(fSalesManager);
      //fSalesManager.Work('The best moneymaker'); // => Error: identifier idents no member "Work"
      ShowInfo(fSalesManager);
    end.

    output:

    -1-
    THuman.Create
    THumanInfo.Create
      this text should not appear
      -1
      -1
    -2-
    TSales.Create
    THumanInfo.Create
    TSalesInfo.Create
      this text should not appear
      -1
      -1
    -3-
    TManager.Create
    THumanInfo.Create
    TManagerInfo.Create
      this text should not appear
      -1
      -1
      this text should not appear
      -1
      -1
    -4-
    TSalesManager.Create
    THumanInfo.Create
    TSalesInfo.Create
    TManagerInfo.Create
      this text should not appear
      -1
      -1
      this text should not appear
      -1
      -1

     


  2. 19 hours ago, Remy Lebeau said:

    Interfaces can't have 'class' methods, either.

    Okay, so I need one base class for all derived classes to realize that?

     

    My problem is that I don't find any real-world example. Only some stupid, simple examples which are so tiny and don't cover much and especially not how to derive the classes like I need with my example shown.

    That's why I'm asking here, thought someone could show the base structures for the example I can work with to use it for my way more complex problem :classic_happy:


  3. You mean like this? Or do IManager inherit from IHuman?

      ICommon = interface
      [GUID]
        function Work(const msg: String): boolean; virtual; // used for simple extra info
        function Work(p: TObject): boolean; virtual; // used for more complex stuff, contains a reference to another class where this class is a member of
        function AsText(): String; virtual; // show a nice text of all infos
        class function HumanAccepted(const name: String): boolean;
      end;
    
      IHuman = interface(ICommon)
      [GUID]
        function GetContractStart(): Integer; // <-- needed because interfaces don't allow fields
        property StartOfContract: Integer read GetContractStart;
      end;
    
      IManager = interface(ICommon)
      [GUID]
        function GetAmountSubworkers(): Integer;
        property AmountSubWorkers: Integer read GetAmountSubworkers;
      end;
      
      ISales = interface(ICommon)
      [GUID]
        function GetSoldCars(): Integer;
        function GetSoldDrinks(): Integer;
        property SoldCars: Integer read GetSoldCars;
        property SoldDrinks: Integer read GetSoldDrinks;
      end;

    And then I implement a TCommon class based on ICommon? THuman based on IHuman, TManager based on THuman or only from IManager?

     


  4. Thanks but it's still a bit unclear to me.

    I need to declare following interfaces, right?

      IHuman = interface
      [GUID]
        constructor Create(const surname, name: String); virtual;
        function Work(const msg: String): boolean; virtual; // used for simple extra info
        function Work(p: TObject): boolean; virtual; // used for more complex stuff, contains a reference to another class where this class is a member of
        function AsText(): String; virtual; // show a nice text of all infos
        class function HumanAccepted(const name: String): boolean;
        // ...
        function GetContractStart(): Integer; // <-- needed because interfaces don't allow fields
        property StartOfContract: Integer read GetContractStart;
      end;
    
      IManager = interface
      [GUID]
        constructor Create(const surname, name: String); override;
        function Work(const msg: String): boolean; override; // used for simple extra info
        function Work(p: TObject): boolean; override; // used for more complex stuff, contains a reference to another class where this class is a member of
        function AsText(): String; override; // show a nice text of all infos, from TManager fields but also THuman
        // ...
        function GetAmountSubworkers(): Integer;
        property AmountSubWorkers: Integer read GetAmountSubworkers;
      end;
      
      ISales = interface
      [GUID]
        constructor Create(const surname, name: String); override;
        function Work(const msg: String): boolean; override; // used for simple extra info
        function Work(p: TObject): boolean; override; // used for more complex stuff, contains a reference to another class where this class is a member of
        function AsText(): String; override; // show a nice text of all infos, from TSales fields but also THuman
        // ...
        function GetSoldCars(): Integer;
        function GetSoldDrinks(): Integer;
        property SoldCars: Integer read GetSoldCars;
        property SoldDrinks: Integer read GetSoldDrinks;
      end;

    But what then? Do I declare THuman = class(IHuman) and add the needed fields and implement all the functions? And then the same for TManager, TSales (with inheriting from THuman)?

    But how to derive TSalesManager then? Inherit from one of the two classes which provides like a chain of inheritance?

    Also how do I avoid code duplication as interfaces do not implement any functionality. :classic_unsure:

    Would be nice if someone could give me a more detailed example (or also other approaches I could use).

    Thanks!


  5. Hello,
    I need some help with re-designing classes from a legacy program and thus I wanted to ask the experts here for help. 😁
    Right now I have a base class THuman and derive different other classes like TManager, TWorker, TSales. This is done by a class function HumanAccepted at THuman that decides which class is created based on some external information.
    So the example classes are looking like the following:

      THuman = class
      private
        FContractStart: Integer; // year of entry to company
      public
        constructor Create(const surname, name: String); virtual;
        function Work(const msg: String): boolean; virtual; // used for simple extra info
        function Work(p: TObject): boolean; virtual; // used for more complex stuff, contains a reference to another class where this class is a member of
        function AsText(): String; virtual; // show a nice text of all infos
        class function HumanAccepted(const name: String): boolean;
        // ...
        property StartOfContract: Integer read FContractStart;
      end;
    
      TManager = class(THuman)
      private
        FSubWorkers: Integer; // number of workers in his group
      public
        constructor Create(const surname, name: String); override;
        function Work(const msg: String): boolean; override; // used for simple extra info
        function Work(p: TObject): boolean; override; // used for more complex stuff, contains a reference to another class where this class is a member of
        function AsText(): String; override; // show a nice text of all infos, from TManager fields but also THuman
        // ...
        property AmountSubWorkers: Integer read FSubWorkers;
      end;
    
      TSales = class(THuman)
      private
        FSoldCars: Integer; // number of cars sold so far
        FSoldDrinks: Integer; // number of drinks sold so far
      public
        constructor Create(const surname, name: String); override;
        function Work(const msg: String): boolean; override; // used for simple extra info
        function Work(p: TObject): boolean; override; // used for more complex stuff, contains a reference to another class where this class is a member of
        function AsText(): String; override; // show a nice text of all infos, from TSales fields but also THuman
        // ...
        property SoldCars: Integer read FSoldCars;
        property SoldDrinks: Integer read FSoldDrinks;
      end;


    Initially a loop iterates over all TCategoryHandlers and creates the found class (that's what class function HumanAccepted is for) as TCHuman which is then used and appended to a object which needs that info stored in my classes. The definitions as code:

      TCHuman = class of THuman;
      TCategoryHandlers = array[0..3] of TCRelease;
      Handlers: TCategoryHandlers = (THuman, TManager, TWorker, TSales);

     

    However, now I have to redesign it as I need to have e.g. TSalesManager which provides me the properties of THuman, TManager and TSales so if Delphi would allow multiple inheritance that's what I'd choose...
    One idea that came into my mind was to copy all stuff into THuman and use booleans to indicate if it's a manager, sales person, etc and do the actions/outputs based on that but I guess that's not a very good solution at all. :classic_blush:
    So that's were I need you guys, do you have any recommendations what I should do to achieve something easily maintainable (avoid code duplications) and extendable for further classes? One thing I also need to do is in another unit that uses properties based on if base.human is TManager then or if base.human is TSales then to perform specific tasks with that info. And just for clarification but guess it's obviously, TSalesManager would need to call TSales.Work as well as TManager.Work.
    We might also want to use mORMot to save all the information into a database at a later point in time, so this should be an option and be considered now.

    Thanks in advance for any tips or ideas!

×