美文网首页SAP
被很多人误解的 ABAP 关键字:READ-ONLY

被很多人误解的 ABAP 关键字:READ-ONLY

作者: _扫地僧_ | 来源:发表于2024-08-05 10:11 被阅读0次

    本文阅读目录

    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 关键字的定义:

    1. 只用于定义 ABAP 类的公有属性。
    2. READ ONLY 属性可以被任意消费者读取。
    3. 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 的理解,避免踩一些不必要的坑。

    相关文章

      网友评论

        本文标题:被很多人误解的 ABAP 关键字:READ-ONLY

        本文链接:https://www.haomeiwen.com/subject/mymzhjtx.html