11.7.3
I have build a class, but now I have to expand it and some of the Methods will now have to be changed depending on what will be read.
Example:
myBong = New Bong.cls().
I would like to tell the Bong.cls what kind of Bong it now will have to read. i.e.
myBong = New Bong.cls('Sharp')
and then I want to move all Methods to ie. SharpBong.cls, QuoriorBong.cls, so when I refer to
myBong:ReadBong(), I refere to the class in play.
Is this where I would use an Interface?
As David, Rutger, Patrick and others have said, there are a few parts
1) you MUST use interfaces for classes that are Bongs
2) you MAY use the abstract factory/builder pattern to instantiate those (I would recommend that you do)
These things are not only possible in ABL but we (PSC) use them *heavily* in some of the ABL modules that we ship (like the HTTP client and WebHandlers).
There's a repo at github.com/.../Composing_Complex_Apps that contains some before ("start") and after ("solution") code that illustrates what those concepts are, and how to use them. Start with this PDF github.com/.../Composing_Complex_Applications.pdf . There's also a longer, workshop version PDF that covers the same ground and a little more.
Well.. no.
An interface comes to play when you don´t care about "who", but "what". That means exactly the opposite to what you are posting.
When you need some "services" (some specific functionallity) and you don't care about who provides it, then you use an interface that "someone else" provides:
method public IDontCare(input ipifAnInterface as my.inteface.ISomeMethods):
ipifAnIntefface:DoIt('yes!').
end method.
In your case, you need inheritance:
class Bong.
end class.
class Sharp inherits Bong:
method public override ReadBong():
end class.
class Lion inherits Bong:
method public override ReadBong().
end class.
class RealSharp inherits Sharp:
end class.
define variable myBong as Bong no-uno.
myBong = NEW Sharp().
do on error undo, throw:
...
finally
delete object myBong no-error.
end finally.
end.
myBong = NEW Lion().
do on error undo, throw:
..
finaly:
delete object myBong no-error.
end finally.
end.
myBong = NEW RealSharp().
etc..
I've re-read your post, and somehow it sounds like the "factory pattern":
An object which is responsible for instantiating the "right" object to be use.
That means that my previous answer still stands, but instead of instantiating the object directly, you would:
myFactory = new BongFactory().
myBong = myFactory('Sharp').
...
myBong = myFactory('VerySharp').
..
myBong = myFactory('Bong').
I would not recommend this usually, because is a lot of overhead for not a real gain.. but as always, this is a "general rule" not a "fixed rule", it always depends on what exactly are you doing (I've use this approach several times, after making sure that the problem I'm solving with it is more complex than the implementation and use of the factories).
If all of the bong types can execute the same actions, but do it differently, an interface might indeed be useful.
Interface iBong:
method void ring().
end.
define variable myBong as iBong no-undo.
class SharpBong implements iBong.
class LowBong implements iBong.
myBong = new SharpBong().
mybong:ring().
myBong = new LowBong().
mybong:ring().
The interface can do a couple of things for you. Among others:
1. force you to implement the same methods and properties on Classes that have a common ground.
2. allow you to have multiple implementations of the same thing.
I know other people can describe it way better than me, but I hope this helps.
Additional to David: if you do not know the type of Bong at compile time, you probably want to use a factory for that as well. You might want to read up on design patterns. There are several sources on the internet, but www.dofactory.com/.../design-patterns is quite readable, albeit more targeted at c#, but c# syntax is not that different from the ABL
I don't know the Bong at compiletime. I want to use Bong.cls as the "Interface" for my bonghandling. I want to move all content of the Methods from Bong.cls to "subclasses". I got some temp-tables, methods and Properties that is a commen ground for all subclasses that I would like to have in Bong.cls.
It seems like what Rutger Points to is what I want to do... I will try to start there and see where it brings me.
You can still do the same with the factory pattern since it is a good way to instantiate the bong implementation at run time.
You still need an interface to create the blueprint for your various bong classes to be able to define an object handle for the objects that will be created by the factory.
Perhaps the words template and contract are the best ways to describe an interface. You must submit to the contract that is set by an interface. Then when you have defined the variable as that interface, all classes that implement that interface can be assigned to the variable.
Within the factory you can for instance (least fancy solution) build a case statement where you return an new Bong of the type you want.
Exactly, you can create a static method in the Bong class that will return the right subtype for you, something like:
CLASS Bong: METHOD PUBLIC STATIC Bong newBong(pcType AS CHARACTER): CASE pcType: WHEN 'Quorior' THEN RETURN NEW QuoriorBong(). WHEN 'Sharp' THEN RETURN NEW SharpBong(). END CASE. END METHOD. END CLASS.
As David, Rutger, Patrick and others have said, there are a few parts
1) you MUST use interfaces for classes that are Bongs
2) you MAY use the abstract factory/builder pattern to instantiate those (I would recommend that you do)
These things are not only possible in ABL but we (PSC) use them *heavily* in some of the ABL modules that we ship (like the HTTP client and WebHandlers).
There's a repo at github.com/.../Composing_Complex_Apps that contains some before ("start") and after ("solution") code that illustrates what those concepts are, and how to use them. Start with this PDF github.com/.../Composing_Complex_Applications.pdf . There's also a longer, workshop version PDF that covers the same ground and a little more.