本文阅读目录
READ-ONLY 的准确含义
READ-ONLY 的使用场合
READ-ONLY 的使用陷阱
总结
对很多 ABAP 开发人员来说,READ-ONLY 是一个使用频率不高的关键字。
因为用的不多,再加上这个关键字的字面意思,很容易让人误解。
本文通过具体的例子讲解,给大家澄清对于 READ-ONLY 的理解误区。
ABAP 里的 READ-ONLY, 只能用来修饰类的公有属性。
如果我们选中类的某个 private 属性,勾上其 Read-Only 选项然后试图激活,会收到语法错误提示:
addition READ-ONLY is only allowed for the public attributes of a class.
当然,在类的范畴之外的其他任意位置,比如 SE38 的 ABAP 报表,SE37 的 Function Module 里,也无法使用该关键字来修饰一般的 ABAP 变量。
READ-ONLY 的准确含义
SAP 官方文档里,对 READ-ONLY 关键字的定义:
- 只用于定义 ABAP 类的公有属性。
- READ ONLY 属性可以被任意消费者读取。
- READ ONLY 属性,可以在定义该属性的类,子类和友元类内部被修改。
看下面这个简单的类,其公有属性 name,被 READ-ONLY 修饰,初始值为 Jerry.
CLASS zcl_readonly_test DEFINITION
PUBLIC FINAL CREATE PUBLIC .
PUBLIC SECTION.
CLASS-DATA name TYPE string READ-ONLY VALUE 'Jerry'.
CLASS-METHODS work .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_READONLY_TEST IMPLEMENTATION.
METHOD work.
name = 'Tom'.
ENDMETHOD.
ENDCLASS.
下面是该类的消费代码。
WRITE:/ zcl_readonly_test=>name.
zcl_readonly_test=>work( ).
WRITE:/ zcl_readonly_test=>name.
作为该类的消费者,两次打印 name 属性,发现值从 Jerry 变成了 Tom.
有了 SAP 帮助文档的铺垫,对于这种行为也就不觉得奇怪了:READ-ONLY 属性的只读特性,只是相对于类的消费者而言的。
其值在类,子类和友元类的实现体内,仍然可以修改。
因为 name 属性值在类的方法 work 内进行了修改,所以前后两次 WRITE 语句打印的结果有所差异。
如果想在类,子类和友元类的外部修改 READ-ONLY 属性,会收到语法错误:
Write access to the READ-ONLY attribute is not allowed outside the class/interface.
READ-ONLY 的使用场合
从最后实现的效果看,如果不考虑继承的场景,被 READ-ONLY 所修饰的 public 属性,等价于类的实现者,为其提供了 public get 访问方法的 private 属性。
比如下面例子里的 Public READ-Only name 和 Private name1 属性,从使用效果上来说等价。
从表面上看,public READ-ONLY 属性,和 private 属性相比,可以少实现一个 get 方法。
那么这两种等价的方法,性能上有没有差异呢?
下面这篇博客,作者做了测试,结论是访问 READ-ONLY 属性,其耗费时间只有显式调用 get 方法的 30% 左右。
这个结论是合理的。因为在编程语言里,面向对象编程领域里的类方法调用,较之传统的 primitive 变量读取访问,本来就要付出额外的开销。
不过这些额外的开销,相比于 ABAP 应用程序花费在数据库层面或网络层面执行逻辑的耗费时间,几乎可以忽略不计。
https://zevolving.com/2011/02/read-only-attribute-vs-getter-methods/
READ-ONLY 的陷阱
SAP 帮助文档也强调,READ-ONLY 并不能阻止其公有属性的引用值,通过引用传递的方式,在类的外部被修改其实际内容。
听起来是否觉得有些拗口?
笔者之前的 ABAP 开发教程,曾经详细介绍了 ABAP 里引用变量本身的值,和引用变量指向实际内存区域值的辨析。
用现实生活中的例子来说明。
我们住的公寓好比内存区域。引用变量本身的值,好比是一个个房间的门牌号,比如 301 代表三楼一号。引用变量指向实际内存区域的值,好比该房间内的住户。
我们把前面的例子稍作修改。
公有属性 name,如今类型不再是 String,而是指向 String 类型的引用,再加上 Read-Only 修饰。
这个语义类比成现实生活中的例子,即"房间的门牌号,不允许被修改"。比如某房间的门牌号为 301,不允许被修改为其他的门牌号,比如 302, 401 之类。
然后在类的构造函数里,给 name 引用指向的实际内存区域的值,赋上初始值 Jerry.
在类的实现体外部,我们试图把 name 属性值,赋给另外一个指向 String 的引用变量 lv,遇到期望中的语法错误:
Write access to the READ-ONLY attribute "NAME" is not allowed outside the class/interface.
但是该只读引用指向的实际内存区域的值,仍然可以在类的外部被修改。
下面的代码,两次打印 READ-ONLY 属性 name 指向的值,第一次打印类内部赋予的初始值 Jerry,第二次打印类外部被修改的新值 Tom.
FIELD-SYMBOLS: <name> TYPE string.
WRITE:/ zcl_readonly_test=>name->*.
ASSIGN zcl_readonly_test=>name->* TO <name>.
<name> = 'Tom'.
WRITE:/ zcl_readonly_test=>name->*.
这就好比房间的门牌号,不能被修改。但是房间里面具体住的人,已经变了。
总结
正因为 READ-ONLY 关键字,会在一定程度上给不明真相的使用者带来理解上的偏差,以及它无法避免引用型的公有属性,其指向的实际内容在类的外部被修改,因此 SAP Clean ABAP 编程规范里针对该关键字的建议是:谨慎使用
。
希望本文能澄清大家对 READ-ONLY 的理解,避免踩一些不必要的坑。
网友评论