为什么我可以动态调用继承的 class public 方法,但不能动态调用受保护的方法?
Why can I dynamically call an inherited class public method, but not a protected one?
问题比较复杂,举个例子给大家解释一下比较容易:
考虑以下 ZCL_FOO
class:
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_FOO
的ZCL_QUX
class:
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 运行ning 它,我会收到一个简短的转储:CX_SY_DYN_CALL_ILLEGAL_METHOD
.
但是,如果我将 xyz
从 PROTECTED 移动到 PUBLIC,我能够 运行 qux->bar( )
成功。
我尝试将 bar 方法更改为使用 CALL METHOD me->(mv_dynamic_method).
,但它也很短转储。
这是 ABAP 错误还是预期功能?在我看来,它不应该short dump。
这是故意的,遵循 object-oriented 设计。
PROTECTED
是一个 one-way 路由:您可以使用它使 parents' 属性在 children 中可见,但反之则不行。您的示例恰好尝试了禁止的相反方向。
更准确地说,任何 class 将永远只能访问自己定义的方法,或作为 public 继承的方法,或受其超级 class 保护的方法。 xyz
既未在 zcl_foo
中定义,也未在超级 class 中定义,因此 zcl_foo
看不到它。
不幸的是,您的示例并没有真正解释为什么您需要该动态调用。 object 方向的典型模式是 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.
然后在每个 sub-class 中覆盖 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.
但是那个模式对我来说真的没有意义。
只是为了好玩,这是按照您的要求执行的错误方法,但任何人都会告诉您永远不要这样做,这是一个非常糟糕的设计,可能会导致许多潜在问题问题 !
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( ).
问题比较复杂,举个例子给大家解释一下比较容易:
考虑以下 ZCL_FOO
class:
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_FOO
的ZCL_QUX
class:
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 运行ning 它,我会收到一个简短的转储:CX_SY_DYN_CALL_ILLEGAL_METHOD
.
但是,如果我将 xyz
从 PROTECTED 移动到 PUBLIC,我能够 运行 qux->bar( )
成功。
我尝试将 bar 方法更改为使用 CALL METHOD me->(mv_dynamic_method).
,但它也很短转储。
这是 ABAP 错误还是预期功能?在我看来,它不应该short dump。
这是故意的,遵循 object-oriented 设计。
PROTECTED
是一个 one-way 路由:您可以使用它使 parents' 属性在 children 中可见,但反之则不行。您的示例恰好尝试了禁止的相反方向。
更准确地说,任何 class 将永远只能访问自己定义的方法,或作为 public 继承的方法,或受其超级 class 保护的方法。 xyz
既未在 zcl_foo
中定义,也未在超级 class 中定义,因此 zcl_foo
看不到它。
不幸的是,您的示例并没有真正解释为什么您需要该动态调用。 object 方向的典型模式是 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.
然后在每个 sub-class 中覆盖 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.
但是那个模式对我来说真的没有意义。
只是为了好玩,这是按照您的要求执行的错误方法,但任何人都会告诉您永远不要这样做,这是一个非常糟糕的设计,可能会导致许多潜在问题问题 !
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( ).