ABAP-OO:(4)封装、继承、多态

面向对象(OO ABAP),最核心的就是掌握「封装、继承、多态」三大特性。这三大特性不仅是OO编程的灵魂,更是SAP标准开发(如BAdI、类池、SAPScript封装)的底层逻辑,学好它们,能让你的代码更简洁、可复用、易维护。

一、封装:把"隐私"藏起来,只暴露有用的接口

1. 什么是封装?

封装就像一个「黑盒子」:把类的核心数据(属性)和逻辑(方法)藏在盒子里,不允许外部直接访问;只对外暴露指定的"接口"(公共方法),外部只能通过接口操作类,无法直接修改内部数据。

举个生活例子:我们用的智能手机,不需要知道内部的芯片、电路板怎么工作(内部逻辑),只需要按"开机""解锁""打电话"按钮(对外接口)就能使用------这就是封装。

2. ABAP中如何实现封装?(核心语法)

ABAP通过「访问控制修饰符」实现封装,核心有3种:

  • PUBLIC(公共):对外暴露,外部可直接访问(接口);

  • PRIVATE(私有):仅类内部可访问,外部无法直接操作(核心隐私数据/逻辑);

  • PROTECTED(保护):类内部+子类可访问,外部不可访问(用于继承场景)。

3. 实操案例:封装一个"安全手机"

需求:手机的「机身序列号」「电池电量」是核心数据,不允许外部直接修改;只暴露"开机""关机""充电""查询电量"的接口,确保数据安全。

复制代码
* 封装后的手机类:核心数据私有化,仅暴露接口
CLASS lcl_mobile DEFINITION.
  PUBLIC SECTION.
    " 对外暴露的接口(公共方法)
    METHODS: constructor IMPORTING iv_sn TYPE string, " 初始化机身序列号
             power_on,                                " 开机
             power_off,                               " 关机
             charge IMPORTING iv_minute TYPE i,       " 充电(分钟)
             get_battery_level RETURNING VALUE(rv_level) TYPE i. " 查询电量

  PRIVATE SECTION.
    " 核心私有属性(外部无法直接访问)
    DATA: gv_sn TYPE char20,         " 机身序列号(唯一标识,不可改)
          gv_battery TYPE i,         " 电池电量(0-100)
          gv_is_on TYPE abap_bool.   " 是否开机

    " 私有方法(内部逻辑,外部不可见)
    METHODS: check_sn. " 内部校验序列号合法性(非空、长度20)
ENDCLASS.

CLASS lcl_mobile IMPLEMENTATION.
  " 构造方法:初始化序列号,调用内部校验,初始化电量
  METHOD constructor.
    gv_sn = iv_sn.
    check_sn( ). " 内部调用私有方法,外部无法直接调用
    gv_battery = 30. " 默认电量30%
    gv_is_on = abap_false.
  ENDMETHOD.

  " 私有方法:校验序列号合法性
  METHOD check_sn.
    IF gv_sn IS INITIAL OR STRLEN( gv_sn ) <> 20.
      MESSAGE '机身序列号不合法(非空、长度20)' TYPE 'E'.
    ENDIF.
  ENDMETHOD.

  " 公共接口:开机
  METHOD power_on.
    IF gv_is_on = abap_false.
      IF gv_battery > 0.
        WRITE: / '手机开机,机身序列号:', gv_sn.
        WRITE: / '当前电量:', gv_battery, '%'.
        gv_is_on = abap_true.
      ELSE.
        WRITE: / '电量不足,无法开机!'.
      ENDIF.
    ELSE.
      WRITE: / '手机已开机!'.
    ENDIF.
  ENDMETHOD.

  " 公共接口:关机
  METHOD power_off.
    IF gv_is_on = abap_true.
      WRITE: / '手机关机',/.
      gv_is_on = abap_false.
    ELSE.
      WRITE: / '手机已关机!',/.
    ENDIF.
  ENDMETHOD.

  " 公共接口:充电(每充电1分钟,电量+1,最高100)
  METHOD charge.
    DATA(lv_add) = iv_minute.
    IF gv_battery + lv_add > 100.
      lv_add = 100 - gv_battery.
    ENDIF.
    gv_battery = gv_battery + lv_add.
    WRITE: / '充电', iv_minute, '分钟,电量增加', lv_add, '%'.
    WRITE: / '当前电量:', gv_battery, '%',/.
  ENDMETHOD.

  " 公共接口:查询电量
  METHOD get_battery_level.
    rv_level = gv_battery.
  ENDMETHOD.
ENDCLASS.

* 主程序测试:只能通过公共接口操作手机
START-OF-SELECTION.
  " 创建手机对象(初始化机身序列号,长度20)
  DATA(lo_mobile) = NEW lcl_mobile( iv_sn = 'SN20240501000000000001' ).

  " 测试公共接口
  lo_mobile->power_on( ).        " 开机(允许)
  lo_mobile->charge( 20 ).       " 充电20分钟(允许)
  DATA(lv_battery) = lo_mobile->get_battery_level( ).
  WRITE: / '查询电量:', lv_battery, '%'.
  lo_mobile->power_off( ).       " 关机(允许)

  " 以下操作会报错(外部无法访问私有属性/方法)
  " lo_mobile->gv_sn = 'SN12345678901234567890'.  " 错误:私有属性不可直接修改
  " lo_mobile->check_sn( ).                      " 错误:私有方法不可直接调用

运行效果:

4. 封装的核心价值(项目中必用)

  • 数据安全:避免外部误操作修改核心数据(比如手机序列号不能随便改);

  • 降低耦合:外部只关心接口用法,不关心内部逻辑,后续修改内部代码不影响外部调用;

  • 代码复用:核心逻辑封装在类中,多个地方可直接创建对象调用。

二、继承:子类"继承"父类的能力,还能自己升级

1. 什么是继承

继承就像"子承父业":子类(子对象)可以继承父类(父对象)的所有公共/保护属性和方法,不用重复编写;同时子类还能新增自己的属性/方法,或者重写父类的方法(前提是父类方法允许重写)。

延续手机案例:基础手机(父类)有"开机、关机、充电、查询电量"功能;智能旗舰手机(子类)继承基础手机的所有功能,还新增"人脸识别解锁""5G联网"等专属功能------这就是继承。

2. ABAP中如何实现继承?(核心语法)

INHERITING FROM 关键字实现继承,核心规则:

  • 子类继承父类的 PUBLICPROTECTED 成员(属性/方法),PRIVATE 成员无法继承;

  • 子类可新增自己的属性/方法,也可重写父类的方法(用 REDEFINE 关键字);

  • 一个子类只能继承一个父类(ABAP不支持多继承)。

3. 实操案例:智能旗舰手机继承基础手机

需求:智能旗舰手机(子类)继承基础手机(父类)的"开机、关机、充电、查询电量"功能,新增"人脸识别解锁""5G联网"功能,并重写"开机"方法(增加人脸识别提示)。

复制代码
* 父类:基础手机(已封装)
CLASS lcl_mobile DEFINITION.
  PUBLIC SECTION.
    METHODS: constructor IMPORTING iv_sn TYPE string,
             power_on,
             power_off,
             charge IMPORTING iv_minute TYPE i,
             get_battery_level RETURNING VALUE(rv_level) TYPE i.

  PROTECTED SECTION.
    DATA: gv_sn TYPE char20,
          gv_battery TYPE i,
          gv_is_on TYPE abap_bool.

  PRIVATE SECTION.
    METHODS: check_sn.
ENDCLASS.

CLASS lcl_mobile IMPLEMENTATION.
  METHOD constructor.
    gv_sn = iv_sn.
    check_sn( ).
    gv_battery = 30.
    gv_is_on = abap_false.
  ENDMETHOD.

  METHOD check_sn.
    IF gv_sn IS INITIAL OR STRLEN( gv_sn ) <> 20.
      MESSAGE '机身序列号不合法(非空、长度20)' TYPE 'E'.
    ENDIF.
  ENDMETHOD.

  METHOD power_on.
    IF gv_is_on = abap_false.
      IF gv_battery > 0.
        WRITE: / '基础手机开机,机身序列号:', gv_sn.
        WRITE: / '当前电量:', gv_battery, '%'.
        gv_is_on = abap_true.
      ELSE.
        WRITE: / '电量不足,无法开机!'.
      ENDIF.
    ELSE.
      WRITE: / '手机已开机!'.
    ENDIF.
  ENDMETHOD.

  METHOD power_off.
    IF gv_is_on = abap_true.
      WRITE: / '手机关机',/.
      gv_is_on = abap_false.
    ELSE.
      WRITE: / '手机已关机!',/.
    ENDIF.
  ENDMETHOD.

  METHOD charge.
    DATA(lv_add) = iv_minute.
    IF gv_battery + lv_add > 100.
      lv_add = 100 - gv_battery.
    ENDIF.
    gv_battery = gv_battery + lv_add.
    WRITE: / '充电', iv_minute, '分钟,电量增加', lv_add, '%'.
    WRITE: / '当前电量:', gv_battery, '%',/.
  ENDMETHOD.

  METHOD get_battery_level.
    rv_level = gv_battery.
  ENDMETHOD.
ENDCLASS.

* 子类:智能旗舰手机(继承基础手机)
CLASS lcl_smart_mobile DEFINITION INHERITING FROM lcl_mobile.
  PUBLIC SECTION.
    " 新增子类专属方法
    METHODS: face_unlock,     " 人脸识别解锁
             a5g_connect.      " 5G联网

    " 重写父类的power_on方法(新增人脸识别提示)
    METHODS: power_on REDEFINITION.
ENDCLASS.

CLASS lcl_smart_mobile IMPLEMENTATION.
  " 重写父类方法:开机,增加人脸识别解锁步骤
  METHOD power_on.
    " 调用父类的power_on方法(保留父类基础功能)
    SUPER->power_on( ).
    " 新增子类功能:人脸识别解锁
    IF gv_is_on = abap_true.
      face_unlock( ).
      WRITE: / '智能旗舰手机:人脸识别解锁成功,可正常使用!',/.
    ENDIF.
  ENDMETHOD.

  " 子类专属方法:人脸识别解锁
  METHOD face_unlock.
    WRITE: / '智能旗舰手机:正在进行人脸识别...'.
    WRITE: / '智能旗舰手机:人脸识别通过'.
  ENDMETHOD.

  " 子类专属方法:5G联网
  METHOD a5g_connect.
    IF gv_is_on = abap_true.
      WRITE: / '智能旗舰手机:已连接5G网络,网速流畅',/.
    ELSE.
      WRITE: / '智能旗舰手机:请先开机再连接网络',/.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

* 主程序测试:子类拥有父类所有功能,还能使用专属功能
START-OF-SELECTION.
  " 创建智能旗舰手机对象(继承父类构造方法,初始化序列号)
  DATA(lo_smart_mobile) = NEW lcl_smart_mobile( iv_sn = 'SN20240501000000000002' ).

  " 调用父类继承的方法
  lo_smart_mobile->charge( 30 ).       " 继承:充电30分钟
  lo_smart_mobile->power_on( ).        " 重写:开机(带人脸识别)
  DATA(lv_battery) = lo_smart_mobile->get_battery_level( ).
  WRITE: / '查询电量:', lv_battery, '%'.
  lo_smart_mobile->power_off( ).       " 继承:关机

  " 调用子类专属方法
  lo_smart_mobile->power_on( ).
  lo_smart_mobile->face_unlock( ).      " 专属:人脸识别解锁
  lo_smart_mobile->a5g_connect( ).      " 专属:5G联网

运行效果:

4. 继承的核心价值(项目中必用)

  • 减少重复代码:父类的通用功能只需编写一次,子类直接继承使用;

  • 便于扩展:子类可在父类基础上新增功能,不修改父类代码(符合"开闭原则");

  • 统一接口:所有子类继承父类的接口,调用方式一致,降低开发成本。

三、多态:同一接口,不同实现(最灵活的特性)

1. 什么是多态?

多态就是"同一动作,不同表现":多个子类继承同一个父类,重写父类的同一个方法;当用父类引用指向不同子类对象时,调用同一个方法,会执行不同子类的实现。

延续手机案例:基础手机、智能旗舰手机、老人手机,都继承"手机"父类,都重写"开机"方法;不管是哪种手机,调用"开机"方法,都会执行各自的逻辑------这就是多态。

2. ABAP中如何实现多态?(核心条件)

实现多态必须满足3个条件:

  • 有继承关系(子类继承父类);

  • 子类重写父类的方法(用REDEFINITION);

  • 用父类类型的引用,指向子类对象(核心:父类引用,子类实例)。

3. 实操案例:多种手机的多态表现

需求:新增"老人手机"子类,和"智能旗舰手机"一起继承基础手机,都重写"开机"方法;用父类引用指向不同子类对象,调用同一个方法,观察不同表现。

复制代码
* 父类:基础手机(统一接口)
CLASS lcl_mobile DEFINITION.
  PUBLIC SECTION.
    METHODS: constructor IMPORTING iv_sn TYPE string,
             power_on. " 父类统一接口,子类将重写

  PROTECTED SECTION.
    DATA: gv_sn TYPE char20,
          gv_battery TYPE i,
          gv_is_on TYPE abap_bool.

  PRIVATE SECTION.
    METHODS: check_sn.
ENDCLASS.

CLASS lcl_mobile IMPLEMENTATION.
  METHOD constructor.
    gv_sn = iv_sn.
    check_sn( ).
    gv_battery = 30.
    gv_is_on = abap_false.
  ENDMETHOD.

  METHOD check_sn.
    IF gv_sn IS INITIAL OR STRLEN( gv_sn ) <> 20.
      MESSAGE '机身序列号不合法(非空、长度20)' TYPE 'E'.
    ENDIF.
  ENDMETHOD.

  METHOD power_on.
    " 父类默认实现(可留空,也可写通用逻辑)
    IF gv_is_on = abap_false.
      IF gv_battery > 0.
        WRITE: / '基础手机开机,机身序列号:', gv_sn.
        WRITE: / '当前电量:', gv_battery, '%',/.
        gv_is_on = abap_true.
      ELSE.
        WRITE: / '电量不足,无法开机!',/.
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

* 子类1:智能旗舰手机(重写power_on)
CLASS lcl_smart_mobile DEFINITION INHERITING FROM lcl_mobile.
  PUBLIC SECTION.
    METHODS: power_on REDEFINITION.
ENDCLASS.

CLASS lcl_smart_mobile IMPLEMENTATION.
  METHOD power_on.
    IF gv_is_on = abap_false.
      IF gv_battery > 0.
        WRITE: / '智能旗舰手机开机:正在进行人脸识别...'.
        WRITE: / '人脸识别通过,机身序列号:', gv_sn.
        WRITE: / '当前电量:', gv_battery, '%,已自动连接5G网络',/.
        gv_is_on = abap_true.
      ELSE.
        WRITE: / '电量不足,无法开机!',/.
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

* 子类2:老人手机(重写power_on)
CLASS lcl_elder_mobile DEFINITION INHERITING FROM lcl_mobile.
  PUBLIC SECTION.
    METHODS: power_on REDEFINITION.
ENDCLASS.

CLASS lcl_elder_mobile IMPLEMENTATION.
  METHOD power_on.
    IF gv_is_on = abap_false.
      IF gv_battery > 0.
        WRITE: / '老人手机开机:大字体模式已开启'.
        WRITE: / '机身序列号:', gv_sn.
        WRITE: / '当前电量:', gv_battery, '%,语音提示:开机成功',/.
        gv_is_on = abap_true.
      ELSE.
        WRITE: / '电量不足,无法开机!',/.
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

* 主程序测试:多态核心------父类引用指向不同子类,调用同一方法
START-OF-SELECTION.
  " 父类类型的引用(核心)
  DATA lo_mobile TYPE REF TO lcl_mobile.

  " 1. 指向智能旗舰手机对象
  lo_mobile = NEW lcl_smart_mobile( iv_sn = 'SN20240501000000000002' ).
  WRITE: '=== 智能旗舰手机开机 ==='.
  lo_mobile->power_on( ). " 执行智能旗舰手机的power_on

  " 2. 指向老人手机对象
  lo_mobile = NEW lcl_elder_mobile( iv_sn = 'SN20240501000000000003' ).
  WRITE: '=== 老人手机开机 ==='.
  lo_mobile->power_on( ). " 执行老人手机的power_on

  " 3. 指向基础手机对象
  lo_mobile = NEW lcl_mobile( iv_sn = 'SN20240501000000000001' ).
  WRITE: '=== 基础手机开机 ==='.
  lo_mobile->power_on( ). " 执行基础手机的power_on

运行效果:

注:这是基于非抽象类,继承多态,子类继承父类(extends)。另外还有抽象类的继承多态,以及接口多态

ABAP OO的三大特性,不是孤立存在的------封装是基础(保证数据安全),继承是前提(实现代码复用),多态是核心(实现灵活扩展)。在实际项目中,我们很少单独使用某一个特性,更多是结合三者(比如SAP标准类的设计、自定义BADI、类池开发)。

相关推荐
duangww1 天前
OPEN SQL去掉文本中间的空格
数据库·abap
HeathlX2 天前
SAP-Fiori:系列(5)Gateway ODATA (V2) CURD之Update
sap·abap
duangww2 天前
SAP订单费用报表
abap
HeathlX4 天前
SAP-Fiori:系列(3)Gateway ODATA (V2) CURD之Create
abap
HeathlX4 天前
SAP-Fiori:系列(4)Gateway ODATA (V2) CURD之Delete
sap·abap
戰皇Hermes5 天前
ABAP cl_document_bcs-用户权限不足导致正文内容变成附件txt
abap
duangww5 天前
SAP 生产订单组件修改
abap
HeathlX5 天前
SAP-Fiori:Gateway ODATA(V2)
abap
HeathlX5 天前
SAP-Fiori:Gateway ODATA (V2) CURD之Query
abap