覆盖 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 覆盖属性是一种不应该使用的糟糕方法。
假设我创建了一个 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 覆盖属性是一种不应该使用的糟糕方法。