特殊OO技术 练习

特殊OO技术 练习

#practice #abstract #final #singleton #factory #friendship #abap-objects

📌核心模式 (点击展开)
关键词 答案
抽象类 CLASS ... DEFINITION ABSTRACT
抽象方法 METHODS ... ABSTRACT,无实现
最终类 CLASS ... DEFINITION FINAL,不能被继承
最终方法 METHODS ... FINAL,不能被重写
单例模式 CREATE PRIVATE + CLASS-DATA + GET_INSTANCE
工厂模式 根据输入返回不同子类实例
友元 CLASS ... DEFINITION FRIENDS ...

题目1 - 抽象类的定义与限制 [记忆]

什么是抽象类(Abstract Class)?在 ABAP 中如何定义?抽象类有哪些限制?

📌查看答案
抽象类定义:抽象类是不能直接实例化的类,只能作为其他类的基类使用。

定义语法

1
2
3
4
5
CLASS lcl_animal DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: make_sound ABSTRACT,
get_name RETURNING VALUE(rv_name) TYPE string.
ENDCLASS.

限制

  • 不能使用 CREATE OBJECT 直接创建抽象类的实例
  • 抽象类中的抽象方法(ABSTRACT)没有实现,必须在具体子类中重写
  • 抽象方法只能在抽象类中定义
  • 抽象类可以同时包含抽象方法和具体方法
  • 子类必须实现所有抽象方法,否则子类也必须是抽象类

使用场景:定义通用接口和部分默认实现,强制子类提供特定行为。


题目2 - Final 类和 Final 方法 [记忆]

什么是最终类(Final Class)和最终方法(Final Method)?它们的设计目的是什么?

📌查看答案
最终类(Final Class)
1
2
3
4
CLASS lcl_utility DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS: convert_string.
ENDCLASS.
  • 整个类不能被继承
  • 最终类中的所有方法隐式为 final

最终方法(Final Method)

1
2
3
4
CLASS lcl_base DEFINITION.
PUBLIC SECTION.
METHODS: get_id FINAL.
ENDCLASS.
  • 该方法不能在子类中被重写(redefined)
  • 最终方法可以在非最终类中定义

设计目的

  1. 安全性:防止子类修改关键行为,确保一致性
  2. 稳定性:保证方法的实现不会被覆盖
  3. 性能:编译器可以对 final 调用进行优化
  4. 设计约束:明确表达设计意图——该扩展点已关闭

注意:ABSTRACTFINAL 不能同时用于同一个方法(矛盾)。但抽象类可以是 final 的(无实际意义)。


题目3 - 单例模式实现 [记忆]

请描述单例模式(Singleton Pattern)在 ABAP 中的完整实现方式,包括类定义和实现。

📌查看答案
单例模式 ABAP 实现
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
26
27
28
29
30
CLASS lcl_singleton DEFINITION
CREATE PRIVATE. " 禁止外部实例化

PUBLIC SECTION.
CLASS-METHODS: get_instance
RETURNING VALUE(ro_instance) TYPE REF TO lcl_singleton.
METHODS: do_something.

PRIVATE SECTION.
CLASS-DATA: mo_instance TYPE REF TO lcl_singleton.
METHODS: constructor.

ENDCLASS.

CLASS lcl_singleton IMPLEMENTATION.
METHOD get_instance.
IF mo_instance IS NOT BOUND.
mo_instance = NEW lcl_singleton( ).
ENDIF.
ro_instance = mo_instance.
ENDMETHOD.

METHOD constructor.
" 初始化逻辑
ENDMETHOD.

METHOD do_something.
" 业务逻辑
ENDMETHOD.
ENDCLASS.

核心要素

  1. CREATE PRIVATE — 外部无法直接 CREATE OBJECT
  2. CLASS-DATA mo_instance — 静态属性保存唯一实例
  3. get_instance( ) — 静态工厂方法,延迟创建并返回实例
  4. 构造函数为 PRIVATE,防止子类和外部调用

线程安全:ABAP 是单线程执行的(每个对话步骤),所以不需要额外的线程同步机制。


题目4 - 工厂模式 [记忆]

什么是工厂模式(Factory Pattern)?在 ABAP 中如何利用继承和接口实现工厂方法?

📌查看答案
工厂模式:定义一个创建对象的接口,让子类决定实例化哪个类。将实例化逻辑与使用逻辑分离。

ABAP 实现示例

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
26
27
28
29
30
31
32
33
34
35
36
37
" 产品接口
INTERFACE lif_document.
METHODS: print,
get_type RETURNING VALUE(rv_type) TYPE string.
ENDINTERFACE.

" 具体产品
CLASS lcl_pdf_doc DEFINITION.
PUBLIC SECTION.
INTERFACES lif_document.
ENDCLASS.

CLASS lcl_word_doc DEFINITION.
PUBLIC SECTION.
INTERFACES lif_document.
ENDCLASS.

" 工厂类
CLASS lcl_doc_factory DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: create_document
IMPORTING iv_type TYPE string
RETURNING VALUE(ro_doc) TYPE REF TO lif_document.
ENDCLASS.

CLASS lcl_doc_factory IMPLEMENTATION.
METHOD create_document.
CASE iv_type.
WHEN 'PDF'.
ro_doc = NEW lcl_pdf_doc( ).
WHEN 'WORD'.
ro_doc = NEW lcl_word_doc( ).
WHEN OTHERS.
" 可抛出异常
ENDCASE.
ENDMETHOD.
ENDCLASS.

使用

1
2
DATA(lo_doc) = lcl_doc_factory=>create_document( 'PDF' ).
lo_doc->print( ). " 多态调用

优点:调用者不需要知道具体类名,只需通过工厂获取对象。


题目5 - 友元关系 (Friendship) [记忆]

什么是 ABAP 中的友元关系(Friendship)?如何定义和使用?它对封装性有什么影响?

📌查看答案
友元关系定义:一个类授予另一个类(或接口)访问其私有(PRIVATE)和受保护(PROTECTED)成员的权限。

定义语法

1
2
3
4
5
6
7
CLASS lcl_internal DEFINITION
FRIENDS lcl_manager. " 授予 lcl_manager 友元权限

PRIVATE SECTION.
DATA: mv_secret TYPE string.
METHODS: private_method.
ENDCLASS.

关键规则

  1. 单向性:友元关系是单向的。如果 A 是 B 的朋友,B 不是 A 的朋友(除非显式声明)
  2. 不可继承:友元关系不能被子类继承
  3. 传递性:如果 A 是 B 的朋友,B 是 C 的朋友,A 不是 C 的朋友
  4. 接口友元:可以将接口声明为友元,实现该接口的类获得友元权限

对封装的影响

  • 友元破坏了严格的封装性,应谨慎使用
  • 适用场景:紧密协作的类之间(如单元测试类访问被测类的私有成员)
  • 不应作为常规设计手段,仅在必要时使用

全局类中的友元

1
2
CLASS zcl_my_class DEFINITION
FRIENDS zcl_test_class. " 允许测试类访问私有成员

题目6 - 抽象与最终组合分析 [分析]

为什么 ABAP 不允许一个方法同时声明为 ABSTRACT 和 FINAL?在什么情况下你会同时使用抽象类和最终类?请分析这种组合的设计意义。

📌查看答案
ABSTRACT + FINAL 矛盾原因
  • ABSTRACT 意味着方法 没有实现,必须在子类中重写
  • FINAL 意味着方法 不能在子类中重写
  • 这两者直接矛盾:一个要求子类必须重写,另一个禁止子类重写

抽象类 + 最终类的组合场景

虽然在方法级别矛盾,但在类级别可以有意义地组合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
" 模板方法模式中的典型应用
CLASS lcl_template DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: template_method FINAL. " 最终方法:固定算法骨架
METHODS: step_one ABSTRACT. " 抽象方法:由子类实现
METHODS: step_two ABSTRACT.
ENDCLASS.

CLASS lcl_template IMPLEMENTATION.
METHOD template_method.
" 固定流程——子类不能改变调用顺序
me->step_one( ).
me->step_two( ).
ENDMETHOD.
ENDCLASS.

设计意义

  1. 模板方法模式:抽象类定义算法骨架(FINAL),子类填充具体步骤(ABSTRACT)
  2. 开放封闭原则:对扩展开放(通过抽象方法),对修改封闭(通过最终方法)
  3. 控制反转:基类控制整体流程,子类只负责具体实现

题目7 - 导航方法 (Navigation Methods) [记忆]

什么是导航方法(Navigation Methods)?它在面向对象设计中有什么作用?请举例说明。

📌查看答案
导航方法定义:导航方法是指通过对象间的关联关系,从一个对象获取到另一个相关对象的引用的方法。

作用

  • 封装对象间的关系,外部不需要了解内部结构
  • 实现对象图中的遍历
  • 隐藏集合或映射的内部实现

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CLASS lcl_order DEFINITION.
PUBLIC SECTION.
METHODS:
" 导航方法:从订单导航到客户
get_customer RETURNING VALUE(ro_customer) TYPE REF TO lcl_customer,
" 导航方法:从订单导航到订单行项目
get_items RETURNING VALUE(rt_items) TYPE lcl_item=>tt_items,
" 导航方法:根据索引获取特定行项目
get_item
IMPORTING iv_index TYPE i
RETURNING VALUE(ro_item) TYPE REF TO lcl_item.
PRIVATE SECTION.
DATA: mo_customer TYPE REF TO lcl_customer,
mt_items TYPE STANDARD TABLE OF REF TO lcl_item.
ENDCLASS.

使用方式

1
2
3
4
5
" 链式导航
DATA(lv_name) = lo_order->get_customer( )->get_name( ).

" 导航到集合
DATA(lt_items) = lo_order->get_items( ).

导航方法是面向对象设计中的基本模式,体现了”告诉对象做什么,而不是向对象要数据”的原则。


题目8 - 设计模式综合应用 [应用]

请设计一个日志系统,要求:1) 使用单例模式确保只有一个日志管理器;2) 使用工厂模式根据日志级别创建不同类型的日志写入器(文件、数据库);3) 使用抽象类定义日志写入器的公共接口。

📌查看答案
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
" ---- 抽象日志写入器 ----
CLASS lcl_log_writer DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: write_log ABSTRACT
IMPORTING iv_message TYPE string
iv_level TYPE char1.
METHODS: get_type ABSTRACT
RETURNING VALUE(rv_type) TYPE string.
ENDCLASS.

" ---- 文件写入器 ----
CLASS lcl_file_writer DEFINITION INHERITING FROM lcl_log_writer.
PUBLIC SECTION.
METHODS: write_log REDEFINITION,
get_type REDEFINITION.
ENDCLASS.
CLASS lcl_file_writer IMPLEMENTATION.
METHOD write_log.
" 写入文件的实现
WRITE: / '[FILE]', iv_level, iv_message.
ENDMETHOD.
METHOD get_type. rv_type = 'FILE'. ENDMETHOD.
ENDCLASS.

" ---- 数据库写入器 ----
CLASS lcl_db_writer DEFINITION INHERITING FROM lcl_log_writer.
PUBLIC SECTION.
METHODS: write_log REDEFINITION,
get_type REDEFINITION.
ENDCLASS.
CLASS lcl_db_writer IMPLEMENTATION.
METHOD write_log.
" 写入数据库的实现
WRITE: / '[DB]', iv_level, iv_message.
ENDMETHOD.
METHOD get_type. rv_type = 'DB'. ENDMETHOD.
ENDCLASS.

" ---- 工厂 ----
CLASS lcl_writer_factory DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: create
IMPORTING iv_type TYPE string
RETURNING VALUE(ro_writer) TYPE REF TO lcl_log_writer.
ENDCLASS.
CLASS lcl_writer_factory IMPLEMENTATION.
METHOD create.
CASE iv_type.
WHEN 'FILE'. ro_writer = NEW lcl_file_writer( ).
WHEN 'DB'. ro_writer = NEW lcl_db_writer( ).
ENDCASE.
ENDMETHOD.
ENDCLASS.

" ---- 单例日志管理器 ----
CLASS lcl_log_manager DEFINITION CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS: get_instance
RETURNING VALUE(ro_mgr) TYPE REF TO lcl_log_manager.
METHODS: log
IMPORTING iv_message TYPE string
iv_level TYPE char1 DEFAULT 'I'.
PRIVATE SECTION.
CLASS-DATA: mo_instance TYPE REF TO lcl_log_manager.
DATA: mo_writer TYPE REF TO lcl_log_writer.
METHODS: constructor.
ENDCLASS.
CLASS lcl_log_manager IMPLEMENTATION.
METHOD get_instance.
IF mo_instance IS NOT BOUND.
mo_instance = NEW lcl_log_manager( ).
ENDIF.
ro_mgr = mo_instance.
ENDMETHOD.
METHOD constructor.
mo_writer = lcl_writer_factory=>create( 'FILE' ).
ENDMETHOD.
METHOD log.
mo_writer->write_log( iv_message = iv_message iv_level = iv_level ).
ENDMETHOD.
ENDCLASS.

" ---- 使用 ----
START-OF-SELECTION.
lcl_log_manager=>get_instance( )->log(
iv_message = '系统启动' iv_level = 'I' ).

📌模式总结 (点击展开)
关键词 答案
抽象类 DEFINITION ABSTRACT,不能实例化
抽象方法 METHODS ... ABSTRACT,无实现,子类必须重写
最终类 DEFINITION FINAL,不能被继承
最终方法 METHODS ... FINAL,不能被重写
单例模式 CREATE PRIVATE + 静态实例 + get_instance
工厂模式 集中创建逻辑,返回接口引用
友元 FRIENDS 关键字,单向授予私有访问权
导航方法 通过方法返回关联对象引用
模板方法 FINAL 方法定义骨架,ABSTRACT 方法定义步骤
ABSTRACT+FINAL 矛盾 方法级别不可共存,类级别可组合使用