Почему я могу динамически вызывать метод publi c унаследованного класса, но не защищенный? - PullRequest
0 голосов
/ 03 апреля 2020

Вопрос сложный, поэтому его проще объяснить на примере:

Рассмотрим следующий ZCL_FOO класс:

CLASS zcl_foo DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.
    METHODS: bar
      RETURNING VALUE(return) TYPE string,
      constructor.
  PROTECTED SECTION.
    DATA: mv_dynamic_method TYPE string.
    METHODS: protected_bar.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_foo IMPLEMENTATION.

  METHOD constructor.
    mv_dynamic_method = 'PROTECTED_BAR'.
  ENDMETHOD.


  METHOD bar.
    CALL METHOD (mv_dynamic_method).

    return = mv_dynamic_method.
  ENDMETHOD.


  METHOD protected_bar.
    WRITE 'protected_bar'.
  ENDMETHOD.
ENDCLASS.

И следующий ZCL_QUX класс , которая наследуется от ZCL_FOO:

CLASS zcl_qux DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC
  INHERITING FROM zcl_foo .

  PUBLIC SECTION.
    METHODS constructor.
  PROTECTED SECTION.
    METHODS xyz.
  PRIVATE SECTION.

ENDCLASS.



CLASS ZCL_QUX IMPLEMENTATION.


  METHOD xyz.
    WRITE 'XYZ'.
  ENDMETHOD.


  METHOD constructor.
    super->constructor( ).
    mv_dynamic_method = 'XYZ'.
  ENDMETHOD.
ENDCLASS.

Обратите внимание, что xyz ЗАЩИЩЕН .

Если я выполню qux->bar( ), например, запустив его через SE24, я получаю короткий дамп: CX_SY_DYN_CALL_ILLEGAL_METHOD.

Однако, если я перейду xyz из ЗАЩИЩЕНО в ПУБЛИ C, я смогу успешно запустить qux->bar( ).

Я пытался изменить метод бара, чтобы использовать CALL METHOD me->(mv_dynamic_method)., но он также сокращал дампы.

Это ошибка ABAP или предполагаемая функция? На мой взгляд, это не должно быть короткой свалкой.

Ответы [ 2 ]

2 голосов
/ 03 апреля 2020

Это преднамеренное и следует объектно-ориентированному дизайну.

PROTECTED - это односторонний маршрут: вы можете использовать его, чтобы сделать атрибуты родителей видимыми у детей, но не наоборот. Ваш пример пробует именно это запрещенное противоположное направление.

Точнее, любой класс сможет когда-либо иметь доступ только к собственным методам, которые были либо определены сами по себе, либо унаследованы как publi c, либо защищены от своего суперкласса. xyz не определен ни в zcl_foo, ни в суперклассе, поэтому zcl_foo не может его увидеть.

К сожалению, ваш пример на самом деле не объясняет, зачем вам нужен этот динамический c вызов. Типичным шаблоном в ориентации объекта будет то, что zcl_foo объявляет xyz как protected, а zcl_qux переопределяет этот метод.

То, что вы могли бы сделать, таково:

CLASS parent DEFINITION PUBLIC CREATE PUBLIC.
  PUBLIC SECTION.
    METHODS call_sub.
  PROTECTED SECTION.
    DATA method_name TYPE string.
ENDCLASS.

CLASS parent IMPLEMENTATION.

  METHOD call_sub.
    CALL METHOD (method_name).
  ENDMETHOD.

ENDCLASS.

Затем переопределите call_sub в каждом подклассе:

CLASS child DEFINITION PUBLIC CREATE PUBLIC
    INHERITING FROM zcl_fh_so_parent.
  PUBLIC SECTION.
    METHODS constructor.
    METHODS call_sub REDEFINITION.
  PROTECTED SECTION.
    METHODS call_me.
ENDCLASS.

CLASS child IMPLEMENTATION.

  METHOD constructor.
    super->constructor( ).
    method_name = `CALL_ME`.
  ENDMETHOD.

  METHOD call_sub.
    CALL METHOD (method_name).
  ENDMETHOD.

  METHOD call_me.
    DATA(success) = 'Hooray!'.
  ENDMETHOD.

ENDCLASS.

Но этот шаблон на самом деле не имеет смысла для меня.

1 голос
/ 03 апреля 2020

Просто для забавы, вот неправильный способ сделать то, что вы просите, но кто-нибудь скажет вам НИКОГДА НЕ ДЕЛАЙТЕ ЭТОГО, ЭТО ОЧЕНЬ ПЛОХОЙ ДИЗАЙН, КОТОРЫЙ МОЖЕТ ПРИВЕСТИ К МНОГИМ ЗАДАЧАМ!

CLASS zcl_foo DEFINITION.
  PUBLIC SECTION.
    METHODS:
      constructor,
      bar
        RETURNING VALUE(return) TYPE string.
  PROTECTED SECTION.
    DATA: mv_dynamic_method TYPE string.
    METHODS: protected_bar.
ENDCLASS.
CLASS zcl_qux DEFINITION
    INHERITING FROM zcl_foo
    FRIENDS zcl_foo. " <==== so that ZCL_FOO may use private/protected members of ZCL_QUX
  PUBLIC SECTION.
    METHODS constructor.
  PROTECTED SECTION.
    METHODS xyz.
ENDCLASS.

CLASS zcl_foo IMPLEMENTATION.
  METHOD constructor.
    mv_dynamic_method = 'PROTECTED_BAR'.
  ENDMETHOD.
  METHOD bar.
    DATA(cast) = CAST object( me ).        " <=========== Cast needed
    CALL METHOD cast->(mv_dynamic_method). " <=========== Cast needed
    return = mv_dynamic_method.
  ENDMETHOD.
  METHOD protected_bar.
    WRITE 'protected_bar'.
  ENDMETHOD.
ENDCLASS.

CLASS zcl_qux IMPLEMENTATION.
  METHOD xyz.
    WRITE 'XYZ'.
  ENDMETHOD.
  METHOD constructor.
    super->constructor( ).
    mv_dynamic_method = 'XYZ'.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA(qux) = NEW zcl_qux( ).
  qux->bar( ).
...