覆盖 ABAP 中的属性 类?

Override attributes in ABAP classes?

假设我创建了一个 class ZCL_WORKORDER_GENERIC,其中一个属性是 ZCL_OPERATIONS_GENERIC 个对象的 table。

现在我想创建一个新的 class ZCL_WORKORDER_SPECIFIC1 继承第一个,但操作列表也应该被 class ZCL_OPERATIONS_SPECIFIC1 覆盖。

在 ABAP 中实现此目标的最佳方法是什么?

假设你有

CLASS zcl_workorder_generic DEFINITION.
  PROTECTED SECTION.
    DATA operations TYPE REF TO zcl_operations_generic.
ENDCLASS.

那么就可以轻松推导

CLASS zcl_workorder_specific1 DEFINITION INHERITING FROM zcl_workorder_generic.
ENDCLASS

子 class 自然可以访问 operations,类型为 zcl_operations_generic

然后你的具体操作就可以

CLASS zcl_operations_specific1 DEFINITION INHERITING FROM zcl_operations_generic.
ENDCLASS.

在面向对象的设计中,zcl_operations_specific1 必须是 zcl_operations_generic 的真正子 class。如果您觉得 add/change 方法 ~specific1 不是 ~generic 的一部分,那么您的面向对象设计是错误的,因为它违反了 Liskov substituion principle。 "Faulty" 这意味着您仍然可以通过大量 CAST 以某种方式使它工作,但是您将违背您的设计而不是让自己被它携带。

无论如何,你应该添加接口。继承是一种在实现之间共享代码的方法。接口在 class 之间声明契约,并为您提供更多独立性,例如在编写单元测试时。

通常您不能覆盖属性,ABAP OO 模型禁止这样做。

但是,您可以使用以下技巧:将 superclass 的属性声明为类型 DATA(又名 data object),然后将您想要的任何类型分配给它sub-class 扩展了你的 superclass.

假设您有两种类型的操作,它们可以唯一标识自己:zcl_operations_generic:

CLASS zcl_operations_generic DEFINITION.
  PUBLIC SECTION.
    DATA l_wheel TYPE char5 VALUE 'wheel'.
  METHODS: identify_me.
ENDCLASS.

CLASS zcl_operations_generic IMPLEMENTATION.
  METHOD identify_me.
    WRITE: `I am `, condense( cl_abap_classdescr=>get_class_name( me ) ), `and I have a`, l_wheel.
  ENDMETHOD.
ENDCLASS.

和更具体的 zcl_operations_specific1

CLASS zcl_operations_specific1 DEFINITION.
  PUBLIC SECTION.
    DATA l_wheel TYPE char10 VALUE 'truckwheel'.
  METHODS: who_am_i.
ENDCLASS.

CLASS zcl_operations_specific1 IMPLEMENTATION.
  METHOD who_am_i.
    WRITE: `I am `, condense( cl_abap_classdescr=>get_class_name( me ) ), `and I have a`, l_wheel.
  ENDMETHOD.
ENDCLASS.

然后在创建通用工单时 zcl_workorder_generic 您将操作 mr_data 指定为通用类型,并在构造函数和方法中进行必要的类型初始化:

CLASS zcl_workorder_generic DEFINITION.
  PUBLIC SECTION.
    DATA mr_data TYPE REF TO data.
    METHODS initialize EXPORTING out_order TYPE ANY.
    METHODS constructor.
ENDCLASS.

CLASS zcl_workorder_generic IMPLEMENTATION.
  METHOD initialize.
    FIELD-SYMBOLS: <lr_data> TYPE REF TO zcl_operations_generic.
    ASSIGN mr_data->* TO <lr_data>.
    CREATE OBJECT <lr_data>.
    out_order = <lr_data>.
  ENDMETHOD.
  METHOD constructor.
    CREATE DATA mr_data TYPE REF TO zcl_operations_generic.
  ENDMETHOD.
ENDCLASS.

并且在特定的工作顺序中 zcl_workorder_specific1 你应该为新类型重新定义 constructor/initialization 方法:

CLASS zcl_workorder_specific1 DEFINITION INHERITING FROM zcl_workorder_generic.
  PUBLIC SECTION.
    METHODS initialize REDEFINITION.
    METHODS constructor.
ENDCLASS.

CLASS zcl_workorder_specific1 IMPLEMENTATION.
  METHOD initialize.
    FIELD-SYMBOLS: <lr_data> TYPE REF TO zcl_operations_specific1.
    ASSIGN mr_data->* TO <lr_data>.
    CREATE OBJECT <lr_data>.
    out_order = <lr_data>.
  ENDMETHOD.
  METHOD constructor.
    super->constructor( ).
    CREATE DATA mr_data TYPE REF TO zcl_operations_specific1.
  ENDMETHOD.
ENDCLASS.

然后你可以像这样实例化你的订单,然后通过调用相应的属性方法检查属性是否正确实例化:

START-OF-SELECTION.

  DATA: generic TYPE REF TO zcl_operations_generic.
  DATA(lr_work_order) = NEW zcl_workorder_generic( ).
  lr_work_order->initialize( IMPORTING out_order = generic ).
  generic->identify_me( ).

  WRITE: /.

  DATA: specific TYPE REF TO zcl_operations_specific1.
  lr_work_order = NEW zcl_workorder_specific1( ).
  lr_work_order->initialize( IMPORTING out_order = specific ).
  specific->who_am_i( ).

但这只是一个棘手的解决方法,我同意 Florian 覆盖属性是一种不应该使用的糟糕方法。