Jump to content

iiid354

Members
  • Content Count

    5
  • Joined

  • Last visited

Everything posted by iiid354

  1. 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. 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!
  2. 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
  3. 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
  4. 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?
  5. 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. Would be nice if someone could give me a more detailed example (or also other approaches I could use). Thanks!
×