In this short post, I will try to explain “friend class” in Abap.

Normally in object oriented programing, visibility of properties of a class is limited with three scopes, Public, protected and private.

 

Public is open to all from anywhere.

Protected is open only to subclasses.

Private is only for classes itself. Normally can not be reached from outside of class.

 

But, with Friend classes you can reach even private properties of an object with out inheritance. That becomes useful when you want to implement factory pattern or in unit testing(Check comments, there is a comment from Paul Hardy!). Please check examples below;

Super class ,ZBMLCL_C_SUPER ,where you define friend classes. In this example only ZBMLCL_C_SUPERS_FRIEND is defined. You can define friend classes from form interface of class too.

CLASS ZBMLCL_C_SUPER DEFINITION
  PUBLIC
  CREATE PUBLIC
  GLOBAL FRIENDS ZBMLCL_C_SUPERS_FRIEND "That means, ZBMLCL_C_SUPERS_FRIEND can read even private properties of this class.
  .

  PUBLIC SECTION.

    DATA: SUPER_DATA_PUBLIC TYPE CHAR1.
    METHODS RETURN_VALUE_PUBLIC RETURNING VALUE(RES) TYPE CHAR1.

  PROTECTED SECTION.
    DATA: SUPER_DATA_PROTECTED TYPE CHAR1.
    METHODS RETURN_VALUE_PROTECTED RETURNING VALUE(RES) TYPE CHAR1.

  PRIVATE SECTION.
    DATA: SUPER_DATA_PRIVATE TYPE CHAR1.
    METHODS RETURN_VALUE_PRIVATE RETURNING VALUE(RES) TYPE CHAR1.
ENDCLASS.



CLASS ZBMLCL_C_SUPER IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZBMLCL_C_SUPER->RETURN_VALUE_PRIVATE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RES                            TYPE        CHAR1
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD RETURN_VALUE_PRIVATE.
    RES = 'S'.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZBMLCL_C_SUPER->RETURN_VALUE_PROTECTED
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RES                            TYPE        CHAR1
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD RETURN_VALUE_PROTECTED.
    RES = 'S'.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZBMLCL_C_SUPER->RETURN_VALUE_PUBLIC
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RES                            TYPE        CHAR1
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD RETURN_VALUE_PUBLIC.
    RES = 'S'.
  ENDMETHOD.
ENDCLASS.

You can define friend classes in Friends tab too.

 

and consuming class ZBMLCL_C_SUPERS_FRIEND ( friend of super )

As you can see in code below, without inheritance, you can use / call protected, even private methods and properties.

CLASS ZBMLCL_C_SUPERS_FRIEND DEFINITION
  PUBLIC
  "INHERITING FROM ZBMLCL_C_SUPER "protected methods and protected properties will be allowed with re-definition of methods
  CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS TEST_FRIEND.

ENDCLASS.
CLASS ZBMLCL_C_SUPERS_FRIEND IMPLEMENTATION.

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZBMLCL_C_SUPERS_FRIEND->TEST_FRIEND
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD TEST_FRIEND.
    DATA(REF_SUPER) = NEW ZBMLCL_C_SUPER( ).

    REF_SUPER->SUPER_DATA_PRIVATE = 'S'. "Because this class is defined as friend in super class
    data(prv) = REF_SUPER->RETURN_VALUE_PRIVATE( ).

    REF_SUPER->SUPER_DATA_PROTECTED = 'S'. "Because this class is defined as friend in super class
    data(prc) = REF_SUPER->RETURN_VALUE_PROTECTED( ).

    REF_SUPER->SUPER_DATA_PUBLIC = 'S'. "That is just public, no need for inheritance or for friend definition
    data(pub) = REF_SUPER->RETURN_VALUE_PUBLIC( ).

    "ME->SUPER_DATA_PROTECTED = 'S'. "Because of inheritence
  ENDMETHOD.
ENDCLASS.

As you can see in this simple example, even without inheritance you can still reach properties of friend class.

 

And here some links to read in depth.

https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenfriends.htm 

https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abapclass_options.htm

 

Addition 12.10.2022 – An example of usage with factory pattern is added, in order to address  the question, that came in comments from Shai.

Below there is a factory class example. An example to understand where friendship can be used, especially with instance creation limitation feature.

Pay attention to create protected and private words in classes. Because of that limitations Mail_SERVER_BASE, LINUX and WINDOWS classes’ instance can not be created publicly and needs to be created via factory class.

 

Base class, declares friendship to an empty interface. So any class that implements interface will have right to access private and protected members and also can create instance of subclasses.

CLASS ZBMLCL_CL_MAIL_SERVER_BASE DEFINITION
 PUBLIC
  CREATE PROTECTED "An Instance can not be created publicly!!!
  GLOBAL FRIENDS ZBMLCL_IF_MAIL_SERVER_FRIEND
  .

  PUBLIC SECTION.

    METHODS SEND_EMAIL
      IMPORTING
        IMPORT_DATA TYPE CHAR1
      EXPORTING
        EXPORT_DATA TYPE CHAR1  .

  PRIVATE SECTION.

    METHODS CREATE_INSTANCE
      IMPORTING
                SERVER_TYPE     TYPE CHAR1
      RETURNING VALUE(INSTANCE) TYPE REF TO ZBMLCL_CL_MAIL_SERVER_BASE.

ENDCLASS.



CLASS ZBMLCL_CL_MAIL_SERVER_BASE IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZBMLCL_CL_MAIL_SERVER_BASE->CREATE_INSTANCE
* +-------------------------------------------------------------------------------------------------+
* | [--->] SERVER_TYPE                    TYPE        CHAR1
* | [<-()] INSTANCE                       TYPE REF TO ZBMLCL_CL_MAIL_SERVER_BASE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD CREATE_INSTANCE.
    TRY.

        CONSTANTS:
          WINSRV TYPE STRING VALUE `ZBMLCL_IF_MAIL_SERVER_WINDOWS`,
          LINSRV TYPE STRING VALUE `ZBMLCL_IF_MAIL_SERVER_LINUX`.

        IF SERVER_TYPE EQ 'W'.
          CREATE OBJECT INSTANCE TYPE (WINSRV).
        ELSE.
          CREATE OBJECT INSTANCE TYPE (LINSRV).
        ENDIF.

      CATCH CX_SY_CREATE_DATA_ERROR
            CX_SY_CREATE_OBJECT_ERROR.
        "Some error logic
    ENDTRY.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZBMLCL_CL_MAIL_SERVER_BASE->SEND_EMAIL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IMPORT_DATA                    TYPE        CHAR1
* | [<---] EXPORT_DATA                    TYPE        CHAR1
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD SEND_EMAIL.
    "raise not implemented !!!
  ENDMETHOD.
ENDCLASS.

 

Empty interface

interface ZBMLCL_IF_MAIL_SERVER_FRIEND
  public .

endinterface.

 

SubClasses

CLASS ZBMLCL_CL_MAIL_SERVER_WINDOWS DEFINITION
  PUBLIC
  INHERITING FROM ZBMLCL_CL_MAIL_SERVER_BASE
  CREATE PRIVATE . "Instance creation is limited!

  PUBLIC SECTION.

    DATA: WIN_PUBLIC_DATA TYPE CHAR1.

    METHODS SEND_EMAIL
        REDEFINITION .

ENDCLASS.
CLASS ZBMLCL_CL_MAIL_SERVER_WINDOWS IMPLEMENTATION.

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZBMLCL_CL_MAIL_SERVER_WINDOWS->SEND_EMAIL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IMPORT_DATA                    TYPE        CHAR1
* | [<---] EXPORT_DATA                    TYPE        CHAR1
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD SEND_EMAIL.
    "Windows server logic to send email
    EXPORT_DATA = 'S'.
  ENDMETHOD.
ENDCLASS.



CLASS ZBMLCL_CL_MAIL_SERVER_LINUX DEFINITION
  PUBLIC
  INHERITING FROM ZBMLCL_CL_MAIL_SERVER_BASE
  CREATE PRIVATE ."Instance creation is limited!

  PUBLIC SECTION.

    METHODS SEND_EMAIL
        REDEFINITION .

ENDCLASS.
CLASS ZBMLCL_CL_MAIL_SERVER_LINUX IMPLEMENTATION.

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZBMLCL_CL_MAIL_SERVER_LINUX->SEND_EMAIL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IMPORT_DATA                    TYPE        CHAR1
* | [<---] EXPORT_DATA                    TYPE        CHAR1
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD SEND_EMAIL.
    "Linux server logic to send email
    EXPORT_DATA = 'S'.
  ENDMETHOD.
ENDCLASS.

 

Factory class that implements interface, therefore has rights to create instances.

CLASS ZBMLCL_CL_MAIL_SERVER_FACTORY DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES ZBMLCL_IF_MAIL_SERVER_FRIEND .

    CLASS-METHODS CREATE_SERVER_INSTANCE
      IMPORTING
        !SERVER_TYPE TYPE CHAR1
      EXPORTING
        SERVER       TYPE REF TO ZBMLCL_CL_MAIL_SERVER_BASE.

  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS ZBMLCL_CL_MAIL_SERVER_FACTORY IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZBMLCL_CL_MAIL_SERVER_FACTORY=>CREATE_SERVER_INSTANCE
* +-------------------------------------------------------------------------------------------------+
* | [--->] SERVER_TYPE                    TYPE        CHAR1
* | [<---] SERVER                         TYPE REF TO ZBMLCL_CL_MAIL_SERVER_BASE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD CREATE_SERVER_INSTANCE.
    TRY.

        CONSTANTS:
          WINSRV TYPE STRING VALUE `ZBMLCL_CL_MAIL_SERVER_WINDOWS`,
          LINSRV TYPE STRING VALUE `ZBMLCL_CL_MAIL_SERVER_LINUX`.

        IF SERVER_TYPE EQ 'W'.
          CREATE OBJECT SERVER TYPE (WINSRV).
        ELSE.
          CREATE OBJECT SERVER TYPE (LINSRV).
        ENDIF.

      CATCH CX_SY_CREATE_DATA_ERROR
            CX_SY_CREATE_OBJECT_ERROR.
        "Some error logic
    ENDTRY.

  ENDMETHOD.
ENDCLASS.

 

And finally instance consumer, mail sender class

CLASS ZBMLCL_CL_MAIL_SEND DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS SEND_MAIL.

  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS ZBMLCL_CL_MAIL_SEND IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZBMLCL_CL_MAIL_SEND=>SEND_MAIL
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD SEND_MAIL.

    "You can not directly create instances!!! Because class creation is limited!

    "Error    An instance of the class "ZBMLCL_CL_MAIL_SERVER_BASE" can only be
    "   created within the class itself or within one of its subclasses.
    "DATA(MAILSERVER) = NEW ZBMLCL_CL_MAIL_SERVER_BASE( ).

    "Error    An instance of the class "ZBMLCL_CL_MAIL_SERVER_WINDOWS" cannot be created outside the class. -
    "DATA(WINMAILSERVER) = NEW ZBMLCL_CL_MAIL_SERVER_WINDOWS( ).

    ZBMLCL_CL_MAIL_SERVER_FACTORY=>CREATE_SERVER_INSTANCE(
      EXPORTING
        SERVER_TYPE = 'W'
      IMPORTING
        SERVER      = DATA(SERVER)
    ).

    SERVER->SEND_EMAIL(
      EXPORTING
        IMPORT_DATA = 'Z'
      IMPORTING
        EXPORT_DATA = DATA(SOMEDATA)
    ).

    "If you want to use full properties of windows type
    DATA:WINSRV TYPE REF TO ZBMLCL_CL_MAIL_SERVER_WINDOWS.
    WINSRV ?= SERVER.
    WINSRV->WIN_PUBLIC_DATA = '1'.

  ENDMETHOD.
ENDCLASS.

 

I hope that helps you.

Please feel free to add your own sample code and examples to comments.

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x