面向对象(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 关键字实现继承,核心规则:
-
子类继承父类的
PUBLIC和PROTECTED成员(属性/方法),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、类池开发)。