Lazarus

Programming => General => Topic started by: Weitentaaal on October 20, 2021, 11:21:45 am

Title: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 11:21:45 am
Hello,

I Have Super-Class and some Sub-Classes. Some of my Sub-Classes will have same Methodes. How can i achiev this.

TSuperClass

TSubClass1 (TSuperClass )
TSubClass2 (TSuperClass )
TSubClass3 (TSuperClass ) \
TSubClass4 (TSuperClass )  |> this three Classes should have a shared Method.
TSubClass5 (TSuperClass ) /

I want to achiev something like this but without inheritance:

Code: Pascal  [Select][+][-]
  1.  
  2. SomeClassWithMethodes = class
  3.    Procedure DoSomething;
  4. end;
  5.  
  6. SubClass3.DoSomething(); //--> Should be able to call this method
  7. SubClass1 //--> Should not See/be able to call this Method
  8.  
  9.  

There will be more than 1 "SomeClassWithMethodes", which is why inheritance is not working.


So in Short: i have a Class, lets say "DataOfSOmething", which provides a Method "DoSomething". Many Different Classes Exist, but only 3 of them Share the Same Method("DoSomething"). If i later on create an instance from one of those 3 classes i would like to call something like this: MyClass.DoSomething. But i can't use Inheritance.
Title: Re: Representing Methods in different Classes
Post by: Zvoni on October 20, 2021, 11:52:51 am
Interfaces?
Title: Re: Representing Methods in different Classes
Post by: MarkMLl on October 20, 2021, 12:19:00 pm
I think the easiest way would be to have a base class (without those extra methods), an intermediate class (which implemented them), and then your final classes which inherited from either the base or the intermediate.

MarkMLl
Title: Re: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 12:35:39 pm
Interfaces?

Can i inherit from a SuperClass and at the Same time implement interfaces ? Something like this:

TClass(TSuperClass, interface1, interface2)

Edit: Wouldn't i have to implement the Method then in every class which uses the interface ? So i would have redundant Code again ?

I think the easiest way would be to have a base class (without those extra methods), an intermediate class (which implemented them), and then your final classes which inherited from either the base or the intermediate.

MarkMLl


the thought i needed  ! thanks ! :)

Nevertheless, I would try it first with interfaces since I have never worked with them.
Title: Re: Representing Methods in different Classes
Post by: Zvoni on October 20, 2021, 12:46:30 pm
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. Uses Classes, SysUtils;
  4.  
  5. Type
  6.   IMyInterface = Interface
  7.      Procedure Method1;
  8.      Procedure Method2;
  9.      Procedure Method3;
  10.   end;
  11.  
  12.   { TSuperClass }
  13.  
  14.   TSuperClass = Class(TInterfacedObject)
  15.     Public
  16.       Procedure PublicMethod;
  17.   end;
  18.   TChildClass1 = Class(TSuperClass)
  19.  
  20.   end;
  21.  
  22.   { TChildClass2 }
  23.  
  24.   TChildClass2 = Class(TSuperClass)
  25.  
  26.   end;
  27.  
  28.   { TChildClass3 }
  29.  
  30.   TChildClass3 = Class(TSuperClass, IMyInterface)
  31.     Public
  32.      Procedure Method1;
  33.      Procedure Method2;
  34.      Procedure Method3;
  35.   end;
  36.   TChildClass4 = Class(TSuperClass, IMyInterface)
  37.     Public
  38.      Procedure Method1;
  39.      Procedure Method2;
  40.      Procedure Method3;
  41.   end;
  42.  
  43.   { TChildClass5 }
  44.  
  45.   TChildClass5 = Class(TSuperClass, IMyInterface)
  46.     Public
  47.      Procedure Method1;
  48.      Procedure Method2;
  49.      Procedure Method3;
  50.   end;
  51.  
  52. { TChildClass5 }
  53.  
  54. procedure TChildClass5.Method1;
  55. begin
  56.   Writeln('Hello From Child5-Method1');
  57. end;
  58.  
  59. procedure TChildClass5.Method2;
  60. begin
  61.   Writeln('Hello From Child5-Method2');
  62. end;
  63.  
  64. procedure TChildClass5.Method3;
  65. begin
  66.   Writeln('Hello From Child5-Method3');
  67. end;
  68.  
  69. { TChildClass3 }
  70.  
  71. procedure TChildClass3.Method1;
  72. begin
  73.   Writeln('Hello From Child3-Method1');
  74. end;
  75.  
  76. procedure TChildClass3.Method2;
  77. begin
  78.   Writeln('Hello From Child3-Method2');
  79. end;
  80.  
  81. procedure TChildClass3.Method3;
  82. begin
  83.   Writeln('Hello From Child3-Method3');
  84. end;
  85.  
  86. procedure TChildClass4.Method1;
  87. Begin
  88.   Writeln('Hello From Child4-Method1');
  89. end;
  90.  
  91. procedure TChildClass4.Method2;
  92. begin
  93.   Writeln('Hello From Child4-Method2');
  94. end;
  95.  
  96. procedure TChildClass4.Method3;
  97. begin
  98.   Writeln('Hello From Child4-Method3');
  99. end;
  100.  
  101. procedure TSuperClass.PublicMethod;
  102. begin
  103.   Writeln('Hello from the Superclass');
  104. end;
  105.  
  106. Procedure CallChildInterface(Const AChild:IMyInterface);
  107. Begin
  108.   AChild.Method1;
  109.   AChild.Method2;
  110.   AChild.Method3;
  111. end;
  112.  
  113. Var
  114.   c1:TChildClass1;
  115.   c2:TChildclass2;
  116.   c3:TChildClass3;
  117.   c4:TChildClass4;
  118.   c5:TChildClass5;
  119.  
  120. begin
  121.   c1:=TChildClass1.Create;
  122.   c1.PublicMethod;
  123.   c1.Free;
  124.   c2:=TChildClass2.Create;
  125.   c2.PublicMethod;
  126.   c2.Free;
  127.   c3:=TChildClass3.Create;
  128.   c3.PublicMethod;
  129.   CallChildInterface(c3);
  130.   c3.Free;
  131.   c4:=TChildClass4.Create;
  132.   c4.PublicMethod;
  133.   CallChildInterface(c4);
  134.   c4.Free;
  135.   c5:=TChildClass5.Create;
  136.   c5.PublicMethod;
  137.   CallChildInterface(c5);
  138.   c5.Free;
  139.   ReadLn;
  140. end.
  141.  
It was just an idea, but i think Mark is closer to the thing you're looking for
Title: Re: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 12:49:40 pm
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. Uses Classes, SysUtils;
  4.  
  5. Type
  6.   IMyInterface = Interface
  7.      Procedure Method1;
  8.      Procedure Method2;
  9.      Procedure Method3;
  10.   end;
  11.  
  12.   { TSuperClass }
  13.  
  14.   TSuperClass = Class(TInterfacedObject)
  15.     Public
  16.       Procedure PublicMethod;
  17.   end;
  18.   TChildClass1 = Class(TSuperClass)
  19.  
  20.   end;
  21.  
  22.   { TChildClass2 }
  23.  
  24.   TChildClass2 = Class(TSuperClass)
  25.  
  26.   end;
  27.  
  28.   { TChildClass3 }
  29.  
  30.   TChildClass3 = Class(TSuperClass, IMyInterface)
  31.     Public
  32.      Procedure Method1;
  33.      Procedure Method2;
  34.      Procedure Method3;
  35.   end;
  36.   TChildClass4 = Class(TSuperClass, IMyInterface)
  37.     Public
  38.      Procedure Method1;
  39.      Procedure Method2;
  40.      Procedure Method3;
  41.   end;
  42.  
  43.   { TChildClass5 }
  44.  
  45.   TChildClass5 = Class(TSuperClass, IMyInterface)
  46.     Public
  47.      Procedure Method1;
  48.      Procedure Method2;
  49.      Procedure Method3;
  50.   end;
  51.  
  52. { TChildClass5 }
  53.  
  54. procedure TChildClass5.Method1;
  55. begin
  56.   Writeln('Hello From Child5-Method1');
  57. end;
  58.  
  59. procedure TChildClass5.Method2;
  60. begin
  61.   Writeln('Hello From Child5-Method2');
  62. end;
  63.  
  64. procedure TChildClass5.Method3;
  65. begin
  66.   Writeln('Hello From Child5-Method3');
  67. end;
  68.  
  69. { TChildClass3 }
  70.  
  71. procedure TChildClass3.Method1;
  72. begin
  73.   Writeln('Hello From Child3-Method1');
  74. end;
  75.  
  76. procedure TChildClass3.Method2;
  77. begin
  78.   Writeln('Hello From Child3-Method2');
  79. end;
  80.  
  81. procedure TChildClass3.Method3;
  82. begin
  83.   Writeln('Hello From Child3-Method3');
  84. end;
  85.  
  86. procedure TChildClass4.Method1;
  87. Begin
  88.   Writeln('Hello From Child4-Method1');
  89. end;
  90.  
  91. procedure TChildClass4.Method2;
  92. begin
  93.   Writeln('Hello From Child4-Method2');
  94. end;
  95.  
  96. procedure TChildClass4.Method3;
  97. begin
  98.   Writeln('Hello From Child4-Method3');
  99. end;
  100.  
  101. procedure TSuperClass.PublicMethod;
  102. begin
  103.   Writeln('Hello from the Superclass');
  104. end;
  105.  
  106. Procedure CallChildInterface(Const AChild:IMyInterface);
  107. Begin
  108.   AChild.Method1;
  109.   AChild.Method2;
  110.   AChild.Method3;
  111. end;
  112.  
  113. Var
  114.   c1:TChildClass1;
  115.   c2:TChildclass2;
  116.   c3:TChildClass3;
  117.   c4:TChildClass4;
  118.   c5:TChildClass5;
  119.  
  120. begin
  121.   c1:=TChildClass1.Create;
  122.   c1.PublicMethod;
  123.   c1.Free;
  124.   c2:=TChildClass2.Create;
  125.   c2.PublicMethod;
  126.   c2.Free;
  127.   c3:=TChildClass3.Create;
  128.   c3.PublicMethod;
  129.   CallChildInterface(c3);
  130.   c3.Free;
  131.   c4:=TChildClass4.Create;
  132.   c4.PublicMethod;
  133.   CallChildInterface(c4);
  134.   c4.Free;
  135.   c5:=TChildClass5.Create;
  136.   c5.PublicMethod;
  137.   CallChildInterface(c5);
  138.   c5.Free;
  139.   ReadLn;
  140. end.
  141.  
It was just an idea, but i think Mark is closer to the thing you're looking for

Well thanks then anyway :)
Title: Re: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 01:05:06 pm
I think the easiest way would be to have a base class (without those extra methods), an intermediate class (which implemented them), and then your final classes which inherited from either the base or the intermediate.

MarkMLl

no matter how i think of it, i always end up with multiple inheritance  %)

Edit1: My Prgramm looks like this:

TSuperClass

TMethodProvidingClass1
TMethodProvidingClass2
TMethodProvidingClass3

TSubClass1(TSuperClass)
TSubClass2(TSuperClass)
TSubClass3(TSuperClass)   //Need TMethodProvidingClass1 and TMethodProvidingClass2
TSubClass4(TSuperClass)   //Need TMethodProvidingClass1
TSubClass5(TSuperClass)   //Need all 3 TMethodProvidingClasses

SubClass1.DoSomething
SubClass2.DoSomething

SubClass3.DoSomethingFromMethodProvidingClass1

SubClass3.DoSomethingFromMethodProvidingClass2
SubClass4.DoSomethingFromMethodProvidingClass1

SubClass5.DoSomethingFromMethodProvidingClass1
SubClass5.DoSomethingFromMethodProvidingClass2
SubClass5.DoSomethingFromMethodProvidingClass3

Title: Re: Representing Methods in different Classes
Post by: MarkMLl on October 20, 2021, 01:10:25 pm
I think the easiest way would be to have a base class (without those extra methods), an intermediate class (which implemented them), and then your final classes which inherited from either the base or the intermediate.

no matter how i think of it, i always end up with multiple inheritance  %)

Why? Show us your code, or at least a tidied-up outline of what you're trying to do.

I've done this fairly heavily in the past: the class side of it works, but there can be problems if you find yourself e.g. trying to extend a classical enumeration with some new error result codes.

MarkMLl
Title: Re: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 01:22:03 pm
Something like this:

Code: Pascal  [Select][+][-]
  1.  
  2. program TestProg;
  3.  
  4. Uses Classes, SysUtils;
  5.  
  6. Type
  7.  
  8.   { TSuperClass }
  9.  
  10.   TSuperClass = Class
  11.     Public
  12.       Procedure SuperMethod;
  13.   end;
  14.  
  15.   TCalcDamperOpeningSize = class
  16.       Procedure CalcThisAndThat(p1, p2, p3: Integer);
  17.   end;
  18.  
  19.   TCalcMotorData = class
  20.       function CalcSomethingElse(p1: integer; p2: Double): Double;
  21.   end;
  22.  
  23.   TChildClass1 = Class(TSuperClass)
  24.  
  25.   end;
  26.  
  27.   TChildClass2 = Class(TSuperClass)
  28.  
  29.   end;
  30.  
  31. Var
  32.   c1:TChildClass1;
  33.   c2:TChildclass2;
  34.  
  35. begin
  36.   c1:=TChildClass1.Create;
  37.   c1.SuperMethod;
  38.   c1.Free;
  39.  
  40.   c2:=TChildClass1.Create;
  41.   c2.SuperMethod;
  42.   c2.CalcThisAndThat //--> how
  43.   c2.CalcSomethingElse // --> how
  44.   c2.Free;
  45. end.
  46.  
  47.  

Child2 has Damper and Motor. Child1 does not. another Class would have a Motor but no Damper
Title: Re: Representing Methods in different Classes
Post by: MarkMLl on October 20, 2021, 02:03:30 pm
Child2 has Damper and Motor. Child1 does not. another Class would have a Motor but no Damper

Ah yes: I can see that being a problem. I don't know whether you could do something there like defining both methods private in the intermediate class and then "surfacing" them to public in the final ones.

Up until very recently I'd have suggested that if the code was non-trivial it could have gone in an include file, but the current problems with rebuilds not always working make me wary of that approach.

I admit that I've always avoided interfaces because of their association with CORBA etc.: I found myself having to look at IDL etc. in the early '90s and it was enough to make me uncomfortable with the whole area... I never had a reason compelling enough to get involved.

MarkMLl
Title: Re: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 02:10:01 pm
"I can see that being a problem. I don't know whether you could do something there like defining both methods private in the intermediate class and then "surfacing" them to public in the final ones."

Guess if there is no "better" solution i will go with that. Thanks anyway for your Time and Effort :)
Title: Re: Representing Methods in different Classes
Post by: egsuh on October 20, 2021, 02:17:40 pm
I think you may define procedural type variable or variable pointing to class with methods, etc.
Title: Re: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 02:36:55 pm
I think you may define procedural type variable or variable pointing to class with methods, etc.

i could also do something like this :

Code: Pascal  [Select][+][-]
  1. procedure DoThisInThat();
  2. begin
  3.    That.DoSomething;
  4. end;
  5.  

but i have all variables in my subclass, which means i would have to hand over like 20 params and that just for 1 single Method.
Same with Results.

Other class would have to see many of my Routines i have in this Subclass because if something is changing then most of the time another Procedure/Function is getting called.

I hope i did not misunderstand what you mean but if i understood it correctly, then its not what i was looking for.

But many thanks for your thoughts :)
Title: Re: Representing Methods in different Classes
Post by: MarkMLl on October 20, 2021, 02:45:01 pm
but i have all variables in my subclass, which means i would have to hand over like 20 params and that just for 1 single Method.
Same with Results.

Put them in a record, or an instance of a class.

MarkMLl
Title: Re: Representing Methods in different Classes
Post by: SymbolicFrank on October 20, 2021, 02:53:52 pm
Make a class "Part", implement one for "Damper" and one for "Motor", add a list of Parts to the main class.
Title: Re: Representing Methods in different Classes
Post by: MarkMLl on October 20, 2021, 02:57:40 pm
Make a class "Part", implement one for "Damper" and one for "Motor", add a list of Parts to the main class.

Yes, that would probably work.

MarkMLl
Title: Re: Representing Methods in different Classes
Post by: Weitentaaal on October 20, 2021, 03:08:36 pm
but i have all variables in my subclass, which means i would have to hand over like 20 params and that just for 1 single Method.
Same with Results.

Put them in a record, or an instance of a class.

MarkMLl


I will try it out !

Make a class "Part", implement one for "Damper" and one for "Motor", add a list of Parts to the main class.

With these 2 solutions i will be able to solve it i guess. If not i will update this Post.

Thanks Guys :)
Title: Re: Representing Methods in different Classes
Post by: Mr.Madguy on October 21, 2021, 06:06:53 am
It's usually done this way:

TSubClass1 (TSuperClass )
TSubClass2 (TSuperClass )
TSuperClass2(TSuperClass) - implements shared method
TSubClass3 (TSuperClass2) \
TSubClass4 (TSuperClass2)  |> this three Classes should have a shared Method.
TSubClass5 (TSuperClass2) /

But true "late binding" can be achieved via multiple inheritance only. Pascal supports limited version of multiple inheritance via interfaces.
Title: Re: Representing Methods in different Classes
Post by: egsuh on October 22, 2021, 09:48:16 am

Try procedural types.  I'm adding to your original codes. I haven't tested following codes myself^^.

Code: Pascal  [Select][+][-]
  1. program TestProg;
  2.  
  3. Uses Classes, SysUtils;
  4.  
  5. Type
  6.  
  7.    TThisAndThat = procedure (i1, i2, i3: integer) of object;
  8.    TSomeThingElse = function (i: integer; d: double): double of object;
  9.  
  10.   { TSuperClass }
  11.  
  12.   TSuperClass = Class
  13.     Public
  14.       Procedure SuperMethod;
  15.   end;
  16.  
  17.   TCalcDamperOpeningSize = class
  18.       Procedure CalcThisAndThat(p1, p2, p3: Integer);
  19.   end;
  20.  
  21.   TCalcMotorData = class
  22.       function CalcSomethingElse(p1: integer; p2: Double): Double;
  23.   end;
  24.  
  25.   TChildClass1 = Class(TSuperClass)
  26.   end;
  27.  
  28.    TChildClass2 = Class(TSuperClass)
  29.    public
  30.          ThisAndThat: TThisAndThat;
  31.          SomeThingElse: TSomeThingElse;
  32.    end;
  33.  
  34. Var
  35.   c1:TChildClass1;
  36.   c2:TChildclass2;
  37.   CalcDamperOpeningSize: TCalcDamperOpeningSize;  
  38.   CalcMotorData: TCalcMotorData;
  39.  
  40. begin
  41.   c1:=TChildClass1.Create;
  42.   c1.SuperMethod;
  43.   c1.Free;
  44.  
  45.    CalcDamperOpeningSize := TCalcDamperOpeningSize.Create;
  46.    CalcMotorData := TCalcMotorData.Create;
  47.  
  48.    c2:=TChildClass1.Create;
  49.    c2.SuperMethod;
  50.  
  51.    C2.ThisAndThat := CalcDamperOpeningSize.CalcThisAndThat;
  52.    C2.SomeThingElse:= CalcMotorData.CalcSomeThingElse;
  53.    c2.ThisAndThat(i1, i2, i3);
  54.    c2.SomethingElse (i1, d1);
  55.  
  56.    c2.Free;
  57.  
  58.    CalcDamperOpeningSize.Free;
  59.    CalcMotorData.Free;
  60.  
  61. end.
  62.  
  63.  
Title: Re: Representing Methods in different Classes
Post by: alpine on October 22, 2021, 10:50:55 am
As of given example, it looks like machine/parts class aggregation example given usually in UML tutorials. If this is the case, you should not derive parts (or machine with) from the machine class itself, but keep them in separate class hierarchy and add them into machine as references.

Same thing that SymbolicFrank advised.
Title: Re: Representing Methods in different Classes
Post by: MarkMLl on October 22, 2021, 11:13:57 am
Same thing that SymbolicFrank advised.

Much the same as I suggested but SymbolicFrank's way is superior since the items can be addressed by name so are extensible.

MarkMLl
Title: Re: Representing Methods in different Classes
Post by: Mr.Madguy on October 22, 2021, 11:31:06 am
There are 3 ways to solve this problem:
1) Interfaces. Problem with this method - extra layer of abstraction, you need to describe - interfaces. They can be treated as abstract classes, that are used to provide access to your classes. In many cases it's done anyway. For example when implementations of classes are separated to DLL. Interfaces are still limited. While one class can implement several interfaces, inheritance between several classes and between several interfaces still has to be single. I.e. if several classes implement several interfaces to one object - they have to be inherited from each other. Otherwise you would need to use class composition and "implements" directive anyway. Interfaces support virtual runtime casting though. I.e. one interface can be casted to any other interface, implemented by the same object, even if one isn't inherited from another.
Code: Pascal  [Select][+][-]
  1. TSuperClass = interface;
  2.  
  3. TSuperClassImplementation = class(TInterfacedObject, TSuperClass);
  4. TSubClassImplementation1 = class(TSuperClassImplementation)
  5.   //Implement your Method 1 here
  6. end;
  7. TSubClassImplementation2 = class(TSuperClassImplementation)
  8.   //Implement your Method 2 here
  9. end;
  10. //etc.
  11. var
  12.   MyObject:TSuperClass;
  13.  
  14. MyObject := TSubClassImplementation1.Create;
  15.  
2) Class composition. As powerful, as multiple inheritance, but is very clunky. You have to do everything manually. I.e. store references to method implementing objects, create them, destroy, etc.
Code: Pascal  [Select][+][-]
  1. //First variant
  2. TAbstractMethodImplementation = class;
  3. //Second variant
  4. TMethod = procedure of object;
  5.  
  6. TMethodImplementation1 = class(TAbstractMethodImplementation);
  7. TMethodImplementation2 = class(TAbstractMethodImplementation);
  8. TMethodImplementation3 = class(TAbstractMethodImplementation);
  9.  
  10. TSuperClass = class
  11. protected
  12.   FMethodImplementation:TAbstractMethodImplementation;
  13.   //For second variant, use FMethod := FMethodImplementation.MyMethod
  14.   FMethod:TMethod;
  15. public
  16.   procedure MyMethod;
  17. end;
  18.  
  19. //Yeah, clunky stubs are needed
  20. procedure TSuperClass.MyMethod;
  21. begin
  22.   FMethodImplementation.MyMethod;
  23.   //Second variant
  24.   //Just call FMethod;
  25. end;
  26.  
  27. TSupClass1 = class(TSuperClass)
  28.   constructor Create;
  29. end;
  30.  
  31. constructor TSupClass1.Create;
  32. begin
  33.   FMethodImplementation := TMethodImplementation1.Create;
  34. end;
  35.  
3) Multiple inheritance (not supported by FPC/Lazarus). Very powerful, but has complications and considered to be overkill, that should be avoided. Just syntax sugar around static objects (i.e. TP-style objects, virtual methods are little bit more complex though). But I personally think, that it's pros are >> than it's cons. One line of code "late binding" - is very powerful thing. Just one line of code allows you to assemble complex class from many different parts, while their code is 100% shared.
Code: Pascal  [Select][+][-]
  1. TInterfaceWithOtherClasses = class;
  2.  
  3. TAbstractMethodImplementation = class(TInterfaceWithOtherClasses:virtual);
  4.  
  5. TMethodImplementation1 = class(TAbstractMethodImplementation);
  6. TMethodImplementation2 = class(TAbstractMethodImplementation);
  7. TMethodImplementation3 = class(TAbstractMethodImplementation);
  8.  
  9. TSuperClass = class(TInterfaceWithOtherClasses:virtual);
  10.  
  11. //FULL POWER OF MULTIPLE INHERITANCE IN JUST ONE LINE OF CODE!!!
  12. TSubClass1 = class(TSuperClass, TMethodImplementation1:override);
  13.  
TinyPortal © 2005-2018