Mark的技术博客

SAP顾问 | 咨询专家 | IT与AI技术探索者

吴让宇(Mark)

吴让宇(Mark)

SAP顾问 | 咨询专家 | IT与AI技术探索者

吴让宇(Mark)的个人技术博客,专注于SAP系统实施、行业方案咨询、IT技术与AI技术的研究与分享。

SAP Fiori ABAP CDS OData Dify Docker AI LLM

最新文章

屏幕编程 (Dynpro) (★★★★)

#abap #abap-dialog

概述表

概念 要点
Dynpro (屏幕) 屏幕 + 流逻辑
模块池 基于屏幕对话的程序类型
PBO 输出前处理(屏幕显示前运行)
PAI 输入后处理(用户操作后运行)
功能码 标识用户操作(按钮点击、菜单)

屏幕处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. PBO (Process Before Output)
├── 设置屏幕属性
├── 填充默认值
└── MODULE status_0100.

2. 屏幕显示 (SAP GUI 渲染)
└── 用户与屏幕交互

3. PAI (Process After Input)
├── 将屏幕值传输到 ABAP
├── 功能码发送到 OK_CODE 字段
└── MODULE user_command_0100.

4. 确定下一个屏幕
├── SET SCREEN nnn (动态)
└── 屏幕 0 = 返回/结束

屏幕组件

组件 描述
布局 可视化排列(屏幕绘制器)
属性 屏幕编号、类型、下一屏幕
元素列表 字段、按钮、OK 代码字段
流逻辑 PBO 和 PAI 模块调用

流逻辑语法

1
2
3
4
5
PROCESS BEFORE OUTPUT.
MODULE status_0100.

PROCESS AFTER INPUT.
MODULE user_command_0100.

OK 代码字段

1
2
3
4
5
6
7
8
9
10
" 在 TOP include 中:
DATA ok_code TYPE syucomm.

" 在 PAI 模块中:
CASE ok_code.
WHEN 'GO'. SET SCREEN 200.
WHEN 'BACK'. SET SCREEN 100.
WHEN 'EXIT'. SET SCREEN 0.
ENDCASE.
CLEAR ok_code.

屏幕导航

语句 作用
SET SCREEN nnn 设置下一个屏幕(在当前 PAI 之后)
LEAVE TO SCREEN nnn 立即跳转到屏幕 nnn
CALL SCREEN nnn 调用屏幕(拥有独立调用栈)
SET SCREEN 0 返回调用屏幕或退出

考试/测试模式

场景/关键词 答案
“PBO 何时运行?” 屏幕显示之前
“PAI 何时运行?” 用户操作之后
“SET SCREEN 0 含义?” 返回调用者或退出
“OK 代码字段用途?” 接收功能码

相关笔记

考试陷阱 (Exam Traps)

#dashboard #exam-traps

⚠️本笔记的目的
考试中容易出错或混淆的重点陷阱集合。

OO编程模型

Trap: 函数组可以实现封装但无法实现多实例
  • 函数组虽然可以封装数据,但一个程序中一个函数组只有一个实例
  • 只有OO编程才能通过类创建多个独立对象实例
  • OO编程模型

UML建模

Trap: 聚合(Aggregation)与组合(Composition)的区别
  • 聚合: 部分可以独立于整体存在(空心菱形)
  • 组合: 部分不能独立于整体存在(实心菱形),生命周期绑定
  • UML类图

类与对象

Trap: READ-ONLY 只能在 PUBLIC SECTION 中使用
  • READ-ONLY 附加项只能在公有可见性部分声明
  • 外部可以读取但不能修改,只有类内部方法可以修改
  • 类属性与方法
Trap: LIKE 在类中只能用于本地数据对象或SY字段
  • 在类的 DATA 语句中,只能使用 TYPE 引用数据类型
  • LIKE 仅允许用于本地数据对象或 SY-DATE, SY-UNAME 等SY字段
  • 类属性与方法
Trap: CLASS 语句不能嵌套
  • 不能在一个类内部定义另一个类
  • 但可以定义局部辅助类(在全局类中)
  • 类属性与方法

继承

Trap: 构造器不被继承
  • 子类必须自己定义构造器(如果需要)
  • 如果子类定义了构造器,必须调用 super->constructor( )
  • 如果子类没有定义构造器,则使用父类的构造器
  • 继承基础
Trap: 方法的重定义 ≠ 重载
  • ABAP Objects 不支持重载(Overloading) — 不能有多个同名不同参的方法
  • 重定义(Redefinition) 是改变继承方法的实现,不改签名
  • 重定义只能在 PUBLIC 或 PROTECTED SECTION 中进行
  • 继承基础
Trap: PROTECTED SECTION 的语法顺序
  • 定义局部类时,必须遵循: PUBLIC SECTION → PROTECTED SECTION → PRIVATE SECTION
  • 顺序不能颠倒
  • 继承基础

类型转换

Trap: Up-cast vs Down-cast 的命名
  • Up-cast (Widening Cast): 子类→父类,= 赋值,隐式安全
  • Down-cast (Narrowing Cast): 父类→子类,?= 赋值,可能运行时错误
  • 名称容易混淆:up-cast 视角变窄但类型兼容性变宽
  • 类型转换与多态
Trap: Down-cast 何时会失败
  • 当引用变量实际指向的对象不是目标类(或其子类)的实例时
  • 会触发 CX_SY_MOVE_CAST_ERROR 运行时异常
  • 类型转换与多态

接口

Trap: 接口组件的可见性
  • 接口中的所有组件都是公有的 — 接口没有可见性分区
  • 但在实现类中,接口组件通过 ~ 操作符访问
  • 别名(ALIASES)受类的可见性规则约束
  • 接口定义与实现
Trap: 接口不能被实例化
  • CREATE OBJECT ref TYPE intf 是不可能的
  • 只能通过实现了接口的类的实例进行 up-cast
  • 接口多态

事件

Trap: 事件处理器的调用顺序不确定
  • 如果多个方法注册到同一事件,调用顺序不保证
  • 不能依赖处理器的执行顺序
  • ABAP事件
Trap: 事件参数只能通过值传递
  • 事件的 EXPORTING 参数必须 VALUE(...) 传递
  • 处理器中用 IMPORTING 接收
  • SENDER 是预定义的隐式参数
  • ABAP事件
Trap: 注册和取消注册
  • SET HANDLER ... ACTIVATION 'X' = 注册(默认)
  • SET HANDLER ... ACTIVATION ' ' = 取消注册
  • FOR ALL INSTANCES 是唯一能注册尚未创建的对象的方式
  • ABAP事件

异常处理

Trap: 三种异常类的区别
  • CX_STATIC_CHECK: 必须在方法签名中声明或在TRY中处理(默认推荐
  • CX_DYNAMIC_CHECK: 运行时检查,不需要显式声明
  • CX_NO_CHECK: 完全不检查,总是可以传播
  • 不能直接继承 CX_ROOT,必须从三个子类之一继承
  • 异常处理概念
Trap: TRY 块中的异常搜索顺序
  • 从最内层 TRY 块开始搜索 CATCH
  • 按 CATCH 语句的出现顺序检查
  • 如果找到匹配(异常类本身或其父类),跳转到该处理器
  • 找不到则向外层扩展搜索
  • 异常处理概念
Trap: CLEANUP 块的执行时机
  • CLEANUP 只在异常被外层或调用者捕获时执行
  • 如果异常在当前 TRY 块内被捕获,CLEANUP 不执行
  • 异常处理概念

RTTS

Trap: RTTI 获取的描述对象需要 Down-cast
  • DESCRIBE_BY_DATA 返回的是 CL_ABAP_TYPEDESCR 类型引用
  • 需要用 ?= (down-cast) 转换为具体子类如 CL_ABAP_STRUCTDESCR
  • 运行时类型服务

  • [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/学习地图]] → 薄弱领域
  • [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/快速参考]]

ABAP Objects 学习地图

#dashboard #abap-objects

概览

  • 课程: BC401 - ABAP Objects (SAP NetWeaver)
  • 时长: 5天
  • 先修课程: SAPTEC, BC400
  • 目标: 掌握 ABAP 面向对象编程的全部概念与技术

主题地图

章节 来源页 笔记 状态
U1: OO编程模型 p.3-14 OO编程模型 [ ]
U1: UML建模 p.15-32 UML类图, UML对象图与序列图 [ ]
U1: OO语法基础 p.33-100 类属性与方法, 对象与引用, 构造器与方法调用 [ ]
U2: 继承与类型转换 p.103-152 继承基础, 类型转换与多态 [ ]
U2: 接口 p.153-197 接口定义与实现, 接口多态 [ ]
U2: 事件 p.198-242 ABAP事件 [ ]
U3: 全局类与接口 p.245-315 Class-Builder, ALV-Grid与BAdI [ ]
U3: 特殊OO技术 p.316-354 抽象类与最终类, 单例工厂与友元 [ ]
U3: 持久化对象 p.355-368 持久化对象与OO事务 [ ]
U4: 异常处理 p.370-419 异常处理概念, 异常处理进阶 [ ]
U4: RTTS p.420-438 运行时类型服务 [ ]

练习笔记

练习集 题目数 链接
OO编程模型 8题 OO编程模型-练习
UML建模 8题 UML建模-练习
OO语法基础 10题 OO语法基础-练习
继承与类型转换 10题 继承与类型转换-练习
接口 8题 接口-练习
事件 8题 事件-练习
全局类与接口 8题 全局类-练习
特殊OO技术 8题 特殊OO技术-练习
持久化对象 8题 持久化对象-练习
异常处理 10题 异常处理-练习
RTTS 8题 运行时类型服务-练习

学习工具

工具 说明 链接
考试陷阱 常见错误和混淆点集合 [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/考试陷阱]]
快速参考 全课程速查表 [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/快速参考]]

标签索引

标签 相关主题 规则
#abap-objects 顶层主题标签 必须出现在所有概念笔记
#oo-basics OO基础 必须与 #abap-objects 共用
#class-definition 类定义语法 附属 #oo-basics
#visibility 可见性/封装 附属 #oo-basics
#constructor 构造器 附属 #oo-basics
#method-call 方法调用 附属 #oo-basics
#uml UML建模 必须与 #abap-objects 共用
#class-diagram 类图 附属 #uml
#association 关联关系 附属 #uml
#inheritance 继承 必须与 #abap-objects 共用
#redefinition 方法重定义 附属 #inheritance
#casting 类型转换 附属 #inheritance
#polymorphism 多态 附属 #inheritance#interface
#interface 接口 必须与 #abap-objects 共用
#alias 别名 附属 #interface
#event 事件 必须与 #abap-objects 共用
#event-handler 事件处理 附属 #event
#global-class 全局类 必须与 #abap-objects 共用
#class-builder Class Builder 附属 #global-class
#alv-grid ALV Grid 附属 #global-class
#badi BAdI技术 附属 #global-class
#abstract-class 抽象类 附属 #special-oo
#final-class 最终类 附属 #special-oo
#singleton 单例模式 附属 #special-oo
#factory 工厂模式 附属 #special-oo
#friendship 友元关系 附属 #special-oo
#persistent-object 持久化对象 附属 #special-oo
#oo-transaction OO事务 附属 #special-oo
#exception 异常处理 必须与 #abap-objects 共用
#try-catch TRY结构 附属 #exception
#raise-exception 抛出异常 附属 #exception
#cx-hierarchy 异常类层次 附属 #exception
#rtts 运行时类型服务 必须与 #abap-objects 共用
#rtti 类型识别 附属 #rtts
#rttc 类型创建 附属 #rtts
#practice 练习题
#dashboard 仪表板
#exam-traps 考试陷阱 附属 #dashboard

标签规则: 所有标签使用英文小写kebab-case;详细标签必须同时附加其父域标签。

薄弱领域

  • 继承中的构造器调用规则 → 继承基础 → [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/考试陷阱]]
  • 接口的down-cast时机 → 接口多态 → [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/考试陷阱]]
  • 事件注册的ALL INSTANCES → ABAP事件 → [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/考试陷阱]]
  • CX_NO_CHECK vs CX_DYNAMIC_CHECK vs CX_STATIC_CHECK → 异常处理概念 → [[_posts/SAP_ABAP/BC401_ABAP对象/00-仪表板/考试陷阱]]

非核心主题策略

来源 内容 处理方式
Unit 5: Preview of Later Topics 后续课程预告 简要覆盖 — 非考试重点
Unit 5: Case Study 综合练习 简要覆盖 — 实践性内容

ABAP Objects 快速参考

#dashboard #abap-objects

类定义 → 类属性与方法

语法 说明
CLASS <name> DEFINITION.ENDCLASS. 类定义部分
CLASS <name> IMPLEMENTATION.ENDCLASS. 类实现部分
PUBLIC SECTION. 公有可见性
PROTECTED SECTION. 受保护可见性
PRIVATE SECTION. 私有可见性

属性类型 → 类属性与方法

语法 类型 说明
DATA: attr TYPE type. 实例属性 每个对象独立
CLASS-DATA: attr TYPE type. 静态属性 所有对象共享
CONSTANTS: c TYPE type VALUE val. 常量 不可变
DATA attr TYPE type READ-ONLY. 只读属性 仅在PUBLIC SECTION中有效

方法定义 → 构造器与方法调用

语法 说明
METHODS: meth IMPORTING ... EXPORTING ... CHANGING ... RETURNING ... RAISING ... 实例方法
CLASS-METHODS: meth ... 静态方法
CALL METHOD ref->meth. 显式方法调用
ref->meth( ). 简写调用
ref->meth( EXPORTING i = v ). 带参数调用
DATA(result) = ref->func_meth( ). 函数式方法调用

对象创建与删除 → 对象与引用

语法 说明
DATA: ref TYPE REF TO <class>. 声明引用变量
CREATE OBJECT ref. 实例化对象
ref->attr 通过引用访问属性
ref->meth( ). 通过引用调用方法

构造器 → 构造器与方法调用

类型 语法 说明
实例构造器 METHODS: constructor IMPORTING ... 每个类只有一个
静态构造器 CLASS-METHODS: class_constructor. 自动调用,无参数

继承 → 继承基础

语法 说明
CLASS subclass DEFINITION INHERITING FROM superclass. 定义继承关系
METHODS: meth REDEFINITION. 重定义方法
super->meth( ). 调用父类方法
me->attr 自引用

类型转换 → 类型转换与多态

类型 语法 说明
Up-cast ( widening ) ref_super = ref_sub. 隐式,总是安全
Down-cast ( narrowing ) ref_sub ?= ref_super. 显式,可能运行时错误
Down-cast (安全) ref_sub = CAST #(<class>( ref_super )). 使用CAST操作符

接口 → 接口定义与实现

语法 说明
INTERFACE <name>.ENDINTERFACE. 定义接口
INTERFACES <name>. (在PUBLIC SECTION中) 实现接口
ref->intf~meth( ). 通过接口解析操作符访问
ALIASES alias FOR intf~meth. 定义别名

事件 → ABAP事件

语法 说明
EVENTS: evt EXPORTING VALUE(e) TYPE t. 定义实例事件
CLASS-EVENTS: evt ... 定义静态事件
RAISE EVENT evt EXPORTING e = val. 触发事件
METHODS: handler FOR EVENT evt OF class IMPORTING e. 定义事件处理器
SET HANDLER ref->handler FOR ref_trigger. 注册事件处理
SET HANDLER ref->handler FOR ALL INSTANCES. 注册到所有实例

异常处理 → 异常处理概念

语法 说明
RAISE EXCEPTION TYPE cx_class EXPORTING ... 抛出异常
TRY. ... CATCH cx_class INTO ref. ... ENDTRY. 捕获异常
CLEANUP. ... 清理块
ref->get_text( ). 获取异常文本

异常类层次 → 异常处理概念

1
2
3
4
5
6
CX_ROOT
├── CX_NO_CHECK (不可声明检查)
├── CX_STATIC_CHECK (静态检查,默认)
└── CX_DYNAMIC_CHECK (动态检查)
└── CX_SY_ARITHMETIC_ERROR
└── CX_SY_ARITHMETIC_OVERFLOW

RTTS → 运行时类型服务

用途
CL_ABAP_TYPEDESCR 根描述类
CL_ABAP_STRUCTDESCR 结构类型描述
CL_ABAP_CLASSDESCR 类类型描述
cl_abap_typedescr=>describe_by_data( data ) 获取数据类型描述
cl_abap_typedescr=>describe_by_object_ref( ref ) 获取对象类型描述

关键公式/模式

模式 公式/规则
实例属性 vs 静态属性 → 类属性与方法 DATA = 每实例, CLASS-DATA = 每类
Up-cast 规则 → 类型转换与多态 子类引用 → 父类引用,隐式安全
Down-cast 规则 → 类型转换与多态 父类引用 → 子类引用,需要 ?=
构造器继承 → 继承基础 构造器不被继承,子类必须调用 super->constructor( )
事件参数 → ABAP事件 事件只能有 EXPORTING 参数(值传递)
异常传播 → 异常处理进阶 方法签名中 RAISING 声明可传播的异常

第 8 单元:程序分析练习(8 道题)

#practice #abap #abap-tools

相关概念

📌关键模式(点击展开)
关键词 答案
代码检查器用途 性能、安全性、语义错误
事务代码 SCI
抑制警告 #EC 伪注释
三大主要类别 性能、安全性、语法

问题 1 - 用途 [recall]

代码检查器分析程序的哪些方面?

📌显示答案
性能(索引使用、循环中的 SELECT)、安全性(跨客户端访问、权限检查不足)以及常见语义错误

问题 2 - 检查变体 [recall]

什么是检查变体?

📌显示答案
决定运行哪些检查。由检查类别和各个可参数化的检查组成。

问题 3 - 对象集 [recall]

对象集定义了什么?

📌显示答案
要检查哪些 Repository 对象。可以是私有的(个人的)或公有的。

问题 4 - 调用方式 [recall]

列出调用代码检查器的三种方式。

📌显示答案
  1. 上下文菜单 → 检查 → 代码检查器
  2. 编辑器菜单 → 检查 → 代码检查器
  3. 事务 SCI

问题 5 - 伪注释 [application]

你的 CALL TRANSACTION 被代码检查器标记。如何处理?

📌显示答案
添加伪注释CALL TRANSACTION 'MM01'. "#EC CI_CALLT

问题 6 - 性能检查 [recall]

列举三个性能检查的例子。

📌显示答案
  • 数据库访问是否使用了索引?
  • 循环中是否有 SELECT 语句?
  • SELECT 是否绕过了缓冲区?

问题 7 - 安全检查 [recall]

代码检查器能检测哪些安全问题?

📌显示答案
  • 跨客户端数据读取
  • 动态 WHERE/表指定
  • 权限检查不足

问题 8 - 默认变体 [analysis]

如果创建名为 DEFAULT 的变体会怎样?

📌显示答案
它会覆盖您用户在所有客户端中的标准默认设置。更好的做法是使用命名变体。删除 DEFAULT 可恢复标准设置。

📌模式总结(点击展开)
关键词 答案
用途 性能、安全性、语义错误
事务 SCI
抑制 #EC 伪注释
默认变体 覆盖您的用户标准设置

UML 序列图 (★★)

#abap-objects #uml

概览表

项目 关键点
序列图 描述对象之间的动态交互和消息传递
生命线 对象存在的时间段
消息 对象之间的方法调用

序列图 (Sequence Diagram)

序列图描述对象之间按时间顺序的交互

  • 纵轴表示时间(从上到下)
  • 横轴表示参与的对象
  • 箭头表示消息/方法调用

序列图元素

1
2
3
4
5
6
7
8
9
对象A            对象B            对象C
│ │ │
│───message1──→ │ │
│ │───message2──→ │
│ │ │
│ │←──return──── │
│←──return───── │ │
│ │ │
× × × ← 销毁
元素 表示 含义
生命线 竖虚线 对象存在期间
同步消息 实心箭头 → 等待返回
返回消息 虚线箭头 ← 方法返回
对象创建 箭头指向新对象 CREATE OBJECT
对象销毁 × 符号 垃圾回收

序列图与ABAP代码的对应

1
2
3
4
序列图:                          ABAP代码:
Agency ──create→ Vehicle CREATE OBJECT vehicle.
Agency ──set_type→ Vehicle vehicle->set_type( ... ).
Agency ──get_speed→ Vehicle speed = vehicle->get_speed( ).
💡序列图是OO交互的可视化
序列图直接映射到代码中的方法调用链,是设计到实现的关键桥梁。

考试/测试模式

场景/关键词 答案
“序列图的用途” 描述对象间按时间顺序的消息交互
“生命线” 表示对象在交互过程中的存在时间
“同步消息” 实心箭头,发送者等待返回

OO语法基础 练习

#practice #oo-syntax #abap-objects

📌核心模式
关键词 答案
类定义 CLASS … DEFINITION / CLASS … IMPLEMENTATION
可见性 PUBLIC SECTION, PROTECTED SECTION, PRIVATE SECTION
构造函数 CONSTRUCTOR 方法,在 CREATE OBJECT 时自动调用
引用变量 TYPE REF TO,指向对象的引用

题目1 - [记忆] 类定义的基本结构

请写出ABAP中定义和实现一个类的完整语法框架。

📌查看答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
" 类定义(声明)
CLASS lcl_example DEFINITION.
PUBLIC SECTION.
" 公有属性和方法声明
PROTECTED SECTION.
" 受保护的属性和方法声明
PRIVATE SECTION.
" 私有属性和方法声明
ENDCLASS.

" 类实现
CLASS lcl_example IMPLEMENTATION.
METHOD method_name.
" 方法实现代码
ENDMETHOD.
ENDCLASS.

关键点:

  • DEFINITION 部分声明类的接口(属性、方法、事件)
  • IMPLEMENTATION 部分实现所有在定义中声明的方法
  • 类名约定:局部类以 LCL_ 开头,全局类以 CL_ 开头

题目2 - [记忆] 三种可见性区域

请解释ABAP类中 PUBLIC SECTION、PROTECTED SECTION 和 PRIVATE SECTION 的区别。

📌查看答案
可见性 访问范围 用途
PUBLIC SECTION 所有外部程序、子类和类本身均可访问 定义外部接口,提供公共服务
PROTECTED SECTION 仅限类本身及其子类(继承者)访问 为子类提供可复用的内部方法和属性
PRIVATE SECTION 仅限类本身访问,子类也无法直接访问 隐藏内部实现细节,保护数据完整性

设计原则:

  • 属性通常设为 PRIVATE,通过公有方法提供受控访问(getter/setter)
  • 供子类重定义的方法放在 PROTECTED SECTION
  • 对外提供的服务接口放在 PUBLIC SECTION
  • 遵循最小可见性原则:尽可能使用最严格的可见性

题目3 - [记忆] 实例属性与静态属性

请说明实例属性(Instance Attribute)和静态属性(Static Attribute)的区别。

📌查看答案
特性 实例属性 静态属性
声明 DATA: attr TYPE type CLASS-DATA: attr TYPE type
存在方式 每个对象实例各有一份独立的副本 整个类只有一份,所有实例共享
访问方式 通过对象引用访问:oref->attr 通过类名访问:lcl_class=>attr,也可通过引用访问
生命周期 随对象的创建和销毁 类被加载时创建,程序运行期间一直存在
典型用途 存储对象的状态数据(如订单金额) 计数器、配置信息、共享常量

示例:

1
2
3
4
5
CLASS lcl_counter DEFINITION.
PUBLIC SECTION.
DATA: count TYPE i. " 实例属性
CLASS-DATA: total TYPE i. " 静态属性
ENDCLASS.

题目4 - [记忆] 构造函数的作用和特点

请说明ABAP中构造函数(CONSTRUCTOR)的特点和用途。

📌查看答案
构造函数的特点:
  1. 名称固定:必须命名为 CONSTRUCTOR(实例构造函数)或 CLASS_CONSTRUCTOR(静态构造函数)
  2. 自动调用:在使用 CREATE OBJECT 创建对象时自动被调用
  3. 初始化:用于设置对象的初始状态,初始化属性值
  4. 参数支持:可以定义 IMPORTING 参数和异常,在创建对象时传入初始值
  5. 不可继承:每个类必须定义自己的构造函数(但子类构造函数会隐式调用父类构造函数)

语法:

1
2
3
4
METHODS: constructor IMPORTING iv_name TYPE string.

" 创建对象时传入参数
CREATE OBJECT lo_obj EXPORTING iv_name = 'Test'.

静态构造函数(CLASS_CONSTRUCTOR):在类首次被访问时自动调用一次,仅用于初始化静态属性,不能有参数。


题目5 - [记忆] 引用变量和对象创建

请说明ABAP中如何声明引用变量、创建对象以及访问对象的属性和方法。

📌查看答案

声明引用变量

1
DATA: lo_customer TYPE REF TO lcl_customer.  " 声明引用变量

创建对象

1
2
3
4
5
CREATE OBJECT lo_customer.                    " 创建对象实例
" 或带参数:
CREATE OBJECT lo_customer
EXPORTING
iv_name = 'John'.

NEW 操作符(内联创建)

1
DATA(lo_customer) = NEW lcl_customer( iv_name = 'John' ).

访问属性和方法

1
2
3
4
5
6
" 实例成员使用 -> (对象组件选择器)
lo_customer->set_name( 'John' ).
DATA(lv_name) = lo_customer->get_name( ).

" 静态成员使用 => (类组件选择器)
DATA(lv_count) = lcl_customer=>instance_count.

关键概念:引用变量存储的是指向对象的指针(引用),而非对象本身。


题目6 - [记忆] 方法定义的参数类型

请列出ABAP方法中可以使用的四种参数类型(参数传递方式)及其特点。

📌查看答案
参数类型 关键字 特点
导入参数 IMPORTING 从调用者传入方法,方法内只读
导出参数 EXPORTING 从方法返回给调用者,方法内写入
变更参数 CHANGING 从调用者传入并可能被方法修改,可读写
返回参数 RETURNING 返回单个值,支持函数式调用链式写法

语法示例:

1
2
3
4
5
METHODS: calculate_price
IMPORTING iv_quantity TYPE i
iv_price TYPE p
EXPORTING ev_total TYPE p
RETURNING VALUE(rv_result) TYPE p.

注意:

  • RETURNING 参数只能有一个,且不能与 EXPORTINGCHANGING 同时使用
  • RETURNING 参数使用 VALUE() 语法,表示按值传递
  • 推荐使用 RETURNING 以支持函数式编程风格

题目7 - [应用] 编写类定义

请根据以下需求编写一个ABAP类的完整定义和实现:

  • 类名:lcl_product(商品类)
  • 有私有的商品名称和价格属性
  • 构造函数接收名称和价格参数进行初始化
  • 公有方法 get_price_with_tax 返回含税价格(税率10%)
📌查看答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CLASS lcl_product DEFINITION.
PUBLIC SECTION.
METHODS:
constructor IMPORTING iv_name TYPE string
iv_price TYPE p DECIMALS 2,
get_price_with_tax RETURNING VALUE(rv_price) TYPE p DECIMALS 2.
PRIVATE SECTION.
DATA:
mv_name TYPE string,
mv_price TYPE p DECIMALS 2.
ENDCLASS.

CLASS lcl_product IMPLEMENTATION.
METHOD constructor.
mv_name = iv_name.
mv_price = iv_price.
ENDMETHOD.

METHOD get_price_with_tax.
rv_price = mv_price * '1.10'.
ENDMETHOD.
ENDCLASS.

使用示例:

1
2
3
DATA(lo_product) = NEW lcl_product( iv_name = '笔记本电脑' iv_price = '5999.00' ).
DATA(lv_tax_price) = lo_product->get_price_with_tax( ).
" lv_tax_price = 6598.90

题目8 - [应用] 方法调用分析

分析以下代码的执行结果。请逐步追踪 lo_ref 引用变量的变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CLASS lcl_demo DEFINITION.
PUBLIC SECTION.
METHODS: set_value IMPORTING iv_val TYPE i.
METHODS: get_value RETURNING VALUE(rv_val) TYPE i.
PRIVATE SECTION.
DATA: mv_value TYPE i.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.
METHOD set_value. mv_value = iv_val. ENDMETHOD.
METHOD get_value. rv_val = mv_value. ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
DATA: lo_ref1 TYPE REF TO lcl_demo.
DATA: lo_ref2 TYPE REF TO lcl_demo.

CREATE OBJECT lo_ref1.
lo_ref1->set_value( 10 ).

lo_ref2 = lo_ref1.
lo_ref2->set_value( 20 ).

WRITE: / lo_ref1->get_value( ).
📌查看答案
输出结果:20

逐步分析:

  1. CREATE OBJECT lo_ref1 — 创建一个 lcl_demo 对象,lo_ref1 指向该对象
  2. lo_ref1->set_value( 10 ) — 将该对象的 mv_value 设置为 10
  3. lo_ref2 = lo_ref1关键步骤:将 lo_ref1 的引用赋值给 lo_ref2,此时 lo_ref1lo_ref2 指向同一个对象(不是创建新对象)
  4. lo_ref2->set_value( 20 ) — 修改了同一对象的 mv_value 为 20
  5. lo_ref1->get_value( ) — 返回该对象的 mv_value,此时值为 20

核心概念:引用赋值(lo_ref2 = lo_ref1)不创建新对象,而是让两个引用变量指向同一块内存。通过任一引用修改对象,另一个引用也能看到变化。


题目9 - [应用] 静态成员使用场景

以下代码试图实现一个对象计数器。请找出代码中的错误并修正。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CLASS lcl_counter DEFINITION.
PUBLIC SECTION.
METHODS: constructor.
DATA: mv_count TYPE i.
PRIVATE SECTION.
CLASS-DATA: gv_instance_count TYPE i.
ENDCLASS.

CLASS lcl_counter IMPLEMENTATION.
METHOD constructor.
gv_instance_count = gv_instance_count + 1.
mv_count = gv_instance_count.
ENDMETHOD.
ENDCLASS.
📌查看答案
代码中的问题:
  1. mv_count 可见性不当mv_count 被定义在 PUBLIC SECTION,外部代码可以随意修改它,破坏了计数器的封装性。应移到 PRIVATE SECTION
  2. 设计问题mv_count(实例属性)在构造函数中被赋值为当前实例编号,但外部可以随意修改。如果目的是为每个实例分配唯一编号,应该通过公有方法提供只读访问

修正版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CLASS lcl_counter DEFINITION.
PUBLIC SECTION.
METHODS:
constructor,
get_instance_number RETURNING VALUE(rv_num) TYPE i,
get_total_instances RETURNING VALUE(rv_count) TYPE i.
PRIVATE SECTION.
DATA: mv_instance_number TYPE i.
CLASS-DATA: gv_instance_count TYPE i.
ENDCLASS.

CLASS lcl_counter IMPLEMENTATION.
METHOD constructor.
gv_instance_count = gv_instance_count + 1.
mv_instance_number = gv_instance_count.
ENDMETHOD.

METHOD get_instance_number.
rv_num = mv_instance_number.
ENDMETHOD.

METHOD get_total_instances.
rv_count = gv_instance_count.
ENDMETHOD.
ENDCLASS.

题目10 - [分析] 方法参数传递方式选择

请分析以下三种方法签名,讨论它们的适用场景以及哪种方式是推荐的最佳实践。

1
2
3
4
5
6
7
8
9
10
11
" 方式A
METHODS: get_full_name
EXPORTING ev_name TYPE string.

" 方式B
METHODS: get_full_name
CHANGING cv_name TYPE string.

" 方式C
METHODS: get_full_name
RETURNING VALUE(rv_name) TYPE string.
📌查看答案
三种方式的对比分析:
特性 方式A (EXPORTING) 方式B (CHANGING) 方式C (RETURNING)
语义 方法输出结果给调用者 方法修改调用者传入的变量 方法返回一个值
调用方式 需要先声明接收变量 需要先初始化传入变量 可直接内联使用
链式调用 不支持 不支持 支持
参数数量 可有多个 可有多个 仅限一个

推荐:方式C(RETURNING)是最佳实践

理由:

  1. 函数式风格:支持链式调用和内联表达式
    1
    2
    " RETURNING 支持这种写法
    lo_person->get_full_name( )->to_upper( ).
  2. 意图清晰:明确表示方法返回一个值,不修改任何已有变量
  3. 代码简洁:无需预先声明接收变量
    1
    2
    3
    4
    5
    6
    " RETURNING
    DATA(lv_name) = lo_person->get_full_name( ).

    " EXPORTING 需要更多代码
    DATA: lv_name TYPE string.
    lo_person->get_full_name( IMPORTING ev_name = lv_name ).

何时用其他方式

  • EXPORTING:方法需要返回多个值时
  • CHANGING:方法需要读取并修改调用者的变量时
  • 一般规则:返回单个值用 RETURNING,返回多个值用 EXPORTING

📌模式总结
关键词 答案
类定义结构 DEFINITION(声明)+ IMPLEMENTATION(实现)
可见性三级 PUBLIC(所有)> PROTECTED(类+子类)> PRIVATE(仅类本身)
实例 vs 静态 DATA(每对象一份)vs CLASS-DATA(全类共享)
构造函数 CONSTRUCTOR自动调用,初始化对象状态
引用赋值 赋值引用不创建新对象,两个引用指向同一实例
参数传递 RETURNING推荐(支持链式),EXPORTING用于多返回值
组件选择器 -> 实例成员,=> 静态成员

UML 类图与对象图 (★★★)

#abap-objects #uml #class-diagram #association

概览表

项目 关键点
类图 描述类的结构、属性、方法及其关系
对象图 描述特定时刻的对象实例及其关系
关联 类之间的连接关系

类图 (Class Diagram)

UML类图是最重要的建模工具之一:

  • 描述系统中类的静态结构
  • 显示类的属性、方法和关系
  • 为OO编程提供蓝图

类的UML表示

1
2
3
4
5
6
7
8
9
10
┌──────────────────────┐
│ Class Name │ ← 类名(大写首字母)
├──────────────────────┤
│ - private_attr: Type │ ← 属性(-私有, +公有, #受保护)
│ + public_attr: Type │
│ # protected_attr: Type│
├──────────────────────┤
│ + method1(): Type │ ← 方法
│ - method2(param: T) │
└──────────────────────┘

可见性符号

符号 含义 ABAP对应
+ 公有 (public) PUBLIC SECTION
- 私有 (private) PRIVATE SECTION
# 受保护 (protected) PROTECTED SECTION

关联关系 (Associations)

关联类型对比

类型 UML表示 含义 生命周期
关联 实线 一般性连接 独立
聚合 空心菱形 + 实线 整体-部分关系 部分可独立存在
组合 实心菱形 + 实线 强整体-部分关系 部分不能独立存在
1
2
3
4
聚合 (Aggregation):           组合 (Composition):
◇────────── ◆──────────
Rental Vehicle Travel Flight
Agency (可独立) Agency (不可独立)

多重性 (Multiplicity)

符号 含义
1 恰好一个
0..1 零或一个
* 零或多个
1..* 一个或多个

对象图 (Object Diagram)

对象图显示特定时刻的对象实例:

  • 对象名带下划线
  • 显示实际的属性值
  • 对象之间的关系用实线连接
1
2
3
4
5
6
7
┌──────────────────────┐
│ myCar: LCL_VEHICLE │ ← 对象名:类名(带下划线)
├──────────────────────┤
│ make = "BMW" │ ← 实际属性值
│ model = "X5" │
│ speed = 120 │
└──────────────────────┘

考试/测试模式

场景/关键词 答案
“聚合与组合的区别” 聚合的”部分”可独立存在,组合的”部分”不能
“可见性符号 - + #” -=私有, +=公有, #=受保护
“多重性 0..1 的含义” 零或一个实例
“对象图 vs 类图” 对象图是类图的实例化快照

经典 ABAP 报表 (★★★★)

#abap #abap-dialog

概述表

概念 要点
可执行程序 (类型 1) 报表程序
选择屏幕 报表的输入参数
列表输出 WRITE 语句输出
事件 控制处理流程

选择屏幕元素

1
2
3
4
PARAMETERS: pa_car TYPE bc400_s_flight-carrid,
pa_con TYPE bc400_s_flight-connid.

SELECT-OPTIONS: so_date FOR bc400_s_flight-fldate.
元素 语法 用途
PARAMETERS 单字段输入 每个字段一个值
SELECT-OPTIONS 范围/复杂选择 多个值、范围、排除条件

事件处理顺序

1
2
3
4
5
1. LOAD-OF-PROGRAM    → 程序加载
2. INITIALIZATION → 默认值(屏幕显示之前)
3. AT SELECTION-SCREEN → 验证输入(用户输入数据之后)
4. START-OF-SELECTION → 主处理(数据库读取、计算)
5. END-OF-SELECTION → 最终输出(可选)
📌INITIALIZATION 时机
INITIALIZATION 在选择屏幕显示之前运行。用于设置动态默认值。
📌START-OF-SELECTION
这是可执行程序的隐式事件块。INITIALIZATION 和下一个事件之间的任何代码都属于 START-OF-SELECTION。

文本元素

类型 用途 维护位置
选择文本 PARAMETERS 字段的标签 文本元素 → 选择文本
列表标题 列/标题文本 文本元素 → 列表标题
文本符号 可重用文本 (text-001) 文本元素 → 文本符号
💡选择文本维护
选择文本在程序的文本元素中维护——而不是直接在选择屏幕上

考试/测试模式

场景/关键词 答案
“设置默认值的事件?” INITIALIZATION(屏幕显示之前)
“主处理事件?” START-OF-SELECTION
“选择文本在哪里维护?” 文本元素中,而不是屏幕上
“SELECT-OPTIONS 的用途?” 范围/复杂选择条件

相关笔记

UML建模 练习

#practice #uml #modeling

📌核心模式
关键词 答案
类图 描述类的结构、属性、方法及类之间的关系
对象图 描述某一时刻对象实例及其关系的快照
关联 类之间的结构关系,表示对象间的连接
序列图 描述对象之间消息传递的时间顺序

题目1 - [记忆] 类图的基本组成

UML类图由哪些基本元素组成?请分别说明每个元素的作用。

📌查看答案
UML类图的基本组成元素:
  1. 类名区域(顶部):显示类的名称,抽象类用斜体表示
  2. 属性区域(中部):列出类的属性,格式为 可见性 名称: 类型,例如 - balance: Decimal
  3. 方法区域(底部):列出类的操作/方法,格式为 可见性 方法名(参数): 返回类型
  4. 可见性符号
    • + 表示 public(公有)
    • - 表示 private(私有)
    • # 表示 protected(受保护)
  5. 关系线:类之间的关联、继承、依赖等关系

题目2 - [记忆] 类图与对象图的区别

请说明UML类图和对象图之间的三个主要区别。

📌查看答案
特性 类图 对象图
表示内容 类的定义(模板/蓝图) 类的实例(具体对象)
名称格式 仅类名,如 Customer 对象名:类名,如 john:Customer,或匿名 :Customer
属性值 仅显示属性名和类型,如 name: String 显示具体的属性值,如 name = "John"
下划线 无下划线 对象名和属性值都加下划线
用途 设计阶段的静态结构描述 描述系统在某一时刻的特定状态/快照

题目3 - [记忆] UML中的关联类型

请列举UML中类之间的四种主要关系类型,并简要说明每种关系的含义。

📌查看答案
  1. 关联(Association):表示两个类之间存在结构关系,对象之间互相知道对方。用实线表示,可标注多重性(如 1..*, 0..1)
  2. 聚合(Aggregation):一种特殊的关联,表示”整体-部分”关系,但部分可以独立于整体存在。用空心菱形表示
  3. 组合(Composition):更强的聚合关系,部分不能独立于整体存在,整体销毁时部分也被销毁。用实心菱形表示
  4. 依赖(Dependency):表示一个类的变化会影响另一个类,通常是临时性的使用关系。用虚线箭头表示

此外还有泛化(Generalization)/继承:子类继承父类,用空心三角箭头表示。


题目4 - [记忆] 序列图的组成元素

UML序列图由哪些基本元素组成?每个元素的作用是什么?

📌查看答案
序列图的基本组成元素:
  1. 参与者/角色(Actor):参与交互的对象或外部角色,放在图的顶部
  2. 生命线(Lifeline):从每个对象向下延伸的虚线,表示对象在时间轴上的存在周期
  3. 激活框(Activation Bar):生命线上的窄矩形,表示对象正在执行操作的时间段
  4. 消息(Message)
    • 同步消息(实心箭头 ):调用者等待返回
    • 异步消息(开放箭头 ):调用者不等待返回
    • 返回消息(虚线箭头 ):表示方法的返回值
  5. 时间轴:从上到下表示时间的先后顺序

题目5 - [记忆] 多重性的表示

在UML类图中,关联关系上的多重性(Multiplicity)有哪些常见的表示方式?请解释每种方式的含义。

📌查看答案
常见的多重性表示:
符号 含义 示例
1 恰好一个 一个订单必须有一个客户
0..1 零个或一个(可选) 一个员工可能没有或有一个经理
*0..* 零个或多个 一个客户可以有零个或多个订单
1..* 一个或多个(至少一个) 一个订单必须至少有一个订单项
n..m 从n到m个 一个团队有3到8个成员

多重性标注在关联线的两端,分别表示该端类的对象数量限制。


题目6 - [应用] 根据场景绘制类图关系

一个在线书店系统有以下需求:

  • 一个客户(Customer)可以下多个订单(Order)
  • 每个订单包含多个订单项(OrderItem)
  • 每个订单项对应一本书(Book)
  • 书属于一个类别(Category)

请描述这些类之间的UML关联关系,包括多重性。

📌查看答案
类之间的关联关系:
  1. Customer → Order

    • Customer 端:1(一个客户)
    • Order 端:0..*(零个或多个订单)
    • 关系:一个客户可以下零个或多个订单
  2. Order → OrderItem

    • Order 端:1(一个订单)
    • OrderItem 端:1..*(一个或多个订单项)
    • 关系:组合关系,订单项不能独立于订单存在
  3. OrderItem → Book

    • OrderItem 端:1..*(每个订单项对应一本书)
    • Book 端:1(一本书)
    • 关系:关联关系
  4. Book → Category

    • Book 端:*(多本书)
    • Category 端:1(属于一个类别)
    • 关系:关联关系,一本书属于一个类别

题目7 - [应用] 读取序列图场景

根据以下交互描述,判断在UML序列图中消息的顺序和类型:

  1. 用户(:User)调用系统(:System)的 login() 方法
  2. 系统调用数据库(:Database)的 authenticate() 方法并等待结果
  3. 数据库返回认证结果
  4. 认证成功后,系统调用会话管理器(:SessionManager)的 createSession() 方法
  5. 系统向用户返回登录结果

请画出消息的顺序并标注消息类型。

📌查看答案
序列图消息顺序(从上到下):
  1. :User → :Systemlogin()同步消息(实心箭头)
  2. :System → :Databaseauthenticate()同步消息(实心箭头)
  3. :Database → :System — 认证结果 — 返回消息(虚线箭头)
  4. :System → :SessionManagercreateSession()同步消息(实心箭头)
  5. :SessionManager → :System — 会话信息 — 返回消息(虚线箭头,隐含)
  6. :System → :User — 登录结果 — 返回消息(虚线箭头)

关键点:

  • 步骤1-3是嵌套调用,系统在等待数据库返回后才继续执行
  • 步骤4发生在步骤3返回之后,表示认证成功后的后续操作
  • 所有消息都是同步的(调用者等待返回)

题目8 - [分析] 选择合适的UML图

在以下三个场景中,你应该选择哪种UML图?请分析理由。

场景A:向新开发人员解释系统中各业务对象的静态结构和关系

场景B:调试一个用户登录流程中对象之间的交互顺序问题

场景C:验证在特定测试用例下,对象的属性值是否正确

📌查看答案

场景A — 选择类图(Class Diagram)

  • 理由:类图描述系统的静态结构,展示所有类、属性、方法以及类之间的关系(关联、继承等)
  • 类图是新开发人员理解系统架构的起点,可以快速了解”系统中有哪些核心对象,它们如何关联”
  • 这是面向对象设计中最基本、最常用的图

场景B — 选择序列图(Sequence Diagram)

  • 理由:序列图专门描述对象之间的动态交互,按时间顺序展示消息传递
  • 调试交互流程问题时,序列图可以清晰显示”谁在什么时候发送了什么消息,返回了什么”
  • 可以直观地发现消息顺序错误、缺少消息或错误的调用关系

场景C — 选择对象图(Object Diagram)

  • 理由:对象图展示类在特定时刻的实例快照,包含具体的属性值
  • 验证特定测试场景下,可以确认”此时刻各对象的属性值是否为预期值”
  • 对象图是类图的实例化,适合用于测试验证和文档示例

总结:静态结构用类图,动态交互用序列图,实例快照用对象图。


📌模式总结
关键词 答案
类图组成 类名 + 属性 + 方法 + 可见性 + 关系线
类图 vs 对象图 类图=模板定义,对象图=实例快照(有下划线和属性值)
四种关系 关联、聚合(空心菱形)、组合(实心菱形)、依赖(虚线)
序列图元素 生命线 + 激活框 + 同步/异步/返回消息
多重性 1, 0..1, , 1.. 表示对象数量约束
图的选择 静态结构→类图,动态交互→序列图,实例验证→对象图
0%