Hi Emir,
I was just tring to complete an example using an Abstract class before changing all my code and then came across something pretty weird.
If I call an instance method in a constructor and then redefine that instance method in a subclass, the redefined method will never be called. Take a look at the following and let me know what you think.
*&---------------------------------------------------------------------*
*& Report ZKP_TEST3
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zkp_test3.
*----------------------------------------------------------------------*
* CLASS mysuper DEFINITION
*----------------------------------------------------------------------*
* Create as abstract so only subclasses can be used create class
* instances
* Create all your inheritable functionality as instance methods
* using the scope to expose specific functionality to subclasses (Protected)
* or classes outside of the class heirarchy (Public)
*----------------------------------------------------------------------*
CLASS mysuper DEFINITION ABSTRACT.
PUBLICSECTION.
METHODS: constructor,
get_my_text RETURNING value(re_text)TYPE string.
" These methods will be visible in all subclasses
PROTECTEDSECTION.
METHODS: initialise,
set_text IMPORTING im_text TYPE string.
" Class Specific Instance
PRIVATESECTION.
DATA: mytext TYPE string.
ENDCLASS. "mysuper DEFINITION
*----------------------------------------------------------------------*
* INTERFACE createable
*----------------------------------------------------------------------*
* Use this interface to expose a factory method to create an instance of
* a subclass.
*
* Once a class implements this it will no longer be possible to inherit
* from it or all subclasses will inherit these static methods
* that cannot be redefined
*----------------------------------------------------------------------*
INTERFACE createable.
" This interface is tightly coupled to all instances of mysuper
" and can be used to create subclasses of this class
" You could have an import param with type ref to data here,
" which could be used to dynamically set import params
CLASS-METHODS: create RETURNING value(re_obj)TYPEREFTO mysuper.
ENDINTERFACE. "createable
*----------------------------------------------------------------------*
* CLASS mysub DEFINITION
*----------------------------------------------------------------------*
* Defined as final as subclasses cannot be redefined and should not
* inherit static factory methods because class type is defined explicitly
* in method (see im_type)
*----------------------------------------------------------------------*
CLASS mysub DEFINITION INHERITING FROM mysuper CREATEPRIVATEFINAL.
PUBLICSECTION.
INTERFACES: createable.
PROTECTEDSECTION.
" Redefined method in subclass to do something more specific
METHODS: initialise REDEFINITION,
constructor.
ENDCLASS. "mysub DEFINITION
DATA: go_super TYPEREFTO mysuper,
l_text TYPE string.
START-OF-SELECTION.
" Instantiation of instances of mysub only possible via this static public method
go_super = mysub=>createable~create().
" Method get_my_text is inherited
l_text = go_super->get_my_text().
WRITE: l_text.
" To do more specific stuff cast go_super to another variable typed
" to mysub
*----------------------------------------------------------------------*
* CLASS mysuper IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS mysuper IMPLEMENTATION.
METHOD initialise.
" Can be redefined in subclass to do something more specific
set_text('I can be super').
ENDMETHOD. "initialise
METHOD constructor.
initialise().
ENDMETHOD. "constructor
METHOD get_my_text.
re_text = mytext.
ENDMETHOD. "get_my_text
METHOD set_text.
mytext = im_text.
ENDMETHOD. "set_text
ENDCLASS. "mysuper IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS mysub IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS mysub IMPLEMENTATION.
METHOD constructor.
super->constructor().
ENDMETHOD. "constructor
METHOD createable~create.
" If you had an import param with type ref to data
" you could parse it here and raise an exception if invalid
" but your option of passing a class that implements an interface
" would also work but you would need to have a public instance attribute
" available to represent your parameter data
" You can now create an instance of your class
DATA: lo_obj TYPEREFTO mysub.
" This should call the super class
" constructor which I thought should invoke the redfined
" initialise method but it never does.
" This code works in Java
CREATEOBJECT lo_obj.
" I can invoke it explicitly here and it works
"lo_obj->initialise( ).
re_obj = lo_obj.
" You can set additional subclass specific methods here
" for functionality that could be handled by the redefined
" initialise method. I.e. handle subclass specific import params
ENDMETHOD. "creatable~create
METHOD initialise.
" Call the super class implementation
super->initialise().
" Set the text to something more specific
set_text('I prefer to be sub').
" If necessary you can call additional instance methods to provide additional functionality
" like re_obj->do_something( ).
ENDMETHOD. "initialise
ENDCLASS. "mysub IMPLEMENTATION
I also created some equivalent code in Java and that works as I expected and the redefined subclass method is called in the constructor.
public final class TestFactory { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub MySub myObj = MySub.create(); System.out.println(myObj.getText()); } }
abstract class MySuper { private String myText; protected MySuper() { initialise(); } public String getText(){ return myText; } protected void setText(String text){ myText = text; } protected void initialise(){ setText("I am Super"); } }
public class MySub extends MySuper { protected MySub() { super(); } protected void initialise(){ super.initialise(); setText("I prefer to be sub"); } public static MySub create(){ return new MySub(); } }
Cheers,
Katan