• ABAP和JavaScript的懒加载,单例和桥接模式的实现和比较


    According to Wikipedia Lazy loading is a design pattern commonly used in computer programming to defer initialization of an object until the point at which it is needed. It can contribute to efficiency in the program’s operation if properly and appropriately used.
    In this blog, I will use an example of SCN log on to illustrate its usage in JavaScript and how to simulate the implementation in ABAP.
    When we click log on link in SCN:

    The whole background of SCN home page turns dark which gives user a hint that something occurs under the hood.

    Let’s assume that SCN creates a dummy div element with proper CSS style to achieve this mask effect. Of course the productive implementation might be completely different and more complex.

    Pseudo Implementation version 1

    Suppose we have a log on button with a click event handler. Every time it is clicked, a new mask div element is created.

    var createMask = function(){
       return document.body.appendChild(  document. createElement('div')  );
    }
    
    $(‘#logon_button').click(function(){
       var mask  = createMask();
       mask.show();
    }) 
    

    Drawback of this version

    Unnecessary mask div element creation. It makes sense to make it a singleton so no matter how many times log on button is clicked, only one mask div element exists.

    Pseudo Implementation version 2

    In this version the mask div element is created in advance.

    var mask = document.body.appendChild(document.createElement('div' ) );
    $( '#logon_button').click(function(){
       mask.show();
    })
    

    Drawback of this version

    In fact it is one variant of singleton design pattern: eager singleton, which means even the log on button is never clicked ( the user just would like to surf the SCN anonymously ), this mask div element is still created in vain.

    Pseudo Implementation version 3

    var mask;
    var createMask = function(){
     if(mask)
        return mask;
     else{
        mask = document,body.appendChild(  document.createElement('div')  );
        return mask;
     }
    }
    

    Drawback of this version

    This version tries to make mask div element lazy loaded: the creation is delayed until it is really needed. And once it is created, its reference is buffered with a global variable mask. It is not a good practice to use global variable to do such task.

    Pseudo Implementation version 4

    var createMask = function() {
      var mask;
      return function() {
           return mask || ( mask = document.body.appendChild(document.createElement('div')));
      }
    }();
    

    In this version, we use closure in JavaScript to achieve the lazy load behavior. The free variable, declared within createMask will not be exposed to external consumer, so it acts actually as a private member attribute in OO world and is the best candidate to buffer the created div element instance. Till now we are very near to the final implementation but this version still have space to improve.

    Drawback of this version

    From single responsibility principle point of view, the function createMask mixes the mask div element creation with element buffering. Is there any approach to decouple these two different tasks?

    Pseudo Implementation version 5 – the final one

    var singleton = function(fn){
        var result;
        return function() {
            return result || ( result = fn.apply(this,arguments));
        }
    }
    var createMask = singleton(function(){
      return document.body.appendChild(document.createElement('div'));
    });
    

    In this version we use a Bridge design pattern to decouple the concrete staff ( mask div element creation ) with the abstract staff ( created element must be singleton ), so that each staff can change independently without influence on the other.

    Lazy Loading in ABAP

    In ABAP actually it is also very easy to implement Lazy Loading: we just declare some private member attribute in class or static variable in function module for instance buffer. Nevertheless, let’s try to simulate the implementation done in JavaScript with Bridge pattern, in order to deepen our understanding on Bridge pattern as an ABAPer.
    I have a dummy class to simulate DOM node:

    class ZCL_DOM_NODE definition
      public
      final
      create public .
    
    public section.
      methods CONSTRUCTOR
        importing
          !IV_NODE_NAME type STRING .
    protected section.
    private section.
      data MV_NODE_NAME type STRING .
    ENDCLASS.
    
    CLASS ZCL_DOM_NODE IMPLEMENTATION.
    method CONSTRUCTOR.
        mv_node_name = iv_node_name.
    endmethod.
    ENDCLASS.
    

    And I have a function module which is dedicatedly responsible for DOM node creation:

    The singleton handling is separately covered another Singleton factory API, which enables any function module with singleton feature by wrapping the original function module, delegating the call to original function module, buffering its call result and returning the buffered result if necessary.

    Let’s first see what is achieved in ABAP.
    This is a test report:

    REPORT zsingleton_test.
    
    DATA(lv_new_fm) = zcl_singleton_factory=>get( iv_func = 'ZCREATE_MASK' ).
    DATA: lo_node1 TYPE REF TO zcl_dom_node,
          lo_node2 TYPE REF TO zcl_dom_node,
          lo_node3 TYPE REF TO zcl_dom_node,
          lo_node4 TYPE REF TO zcl_dom_node.
    CALL FUNCTION lv_new_fm
       EXPORTING
          iv_node_name = 'Jerry'
       IMPORTING
          eo_node = lo_node1.
    
    CALL FUNCTION lv_new_fm
       EXPORTING
          iv_node_name = 'Jerry'
       IMPORTING
          eo_node = lo_node2.
    
    CALL FUNCTION lv_new_fm
       EXPORTING
          iv_node_name = 'Java'
       IMPORTING
          eo_node = lo_node3.
    
    CALL FUNCTION lv_new_fm
       EXPORTING
          iv_node_name = 'Java'
       IMPORTING
          eo_node = lo_node4.
    
    zcl_singleton_factory=>cleanup( ).
    

    A new function module is dynamically generated by ZCL_SINGLETON_FACTORY based on original function module ZCREATE_MASK. The new function module name is stored in variable lv_new_fm.
    The new function module has exactly the same signature as ZCREATE_MASK. When it is called, we can observed that the singleton is fulfilled.

    The automatically created wrapped function module will be cleared by the following call in the end of test report.

    zcl_singleton_factory=>cleanup( ).
    Comment out this statement then we can have a look at the content of generated function module. Here below is one example for ZCREATE_MASK.


    The whole source code of this automatically generated function module are prepared in method ADAPT_SOURCE_CODE:

    The main idea of the function module automatic generation is very similar as introduced in my blog Functional programming – Simulate Curry in ABAP.

    Summary

    In JavaScript, it only takes 6 simply lines to get a singleton factory which can wrap any function to behave with singleton functionality. In fact this is implemented via closure in JavaScript.

    And in ABAP, due to lack of support in language perspective, I spend totally 351 lines of ABAP codes for simulation.
    Hope this small simulation can help you as ABAPers to understand some language features in JavaScript.

    Further reading

    I have written a series of blogs which compare the language feature among ABAP, JavaScript and Java. You can find a list of them below:

    要获取更多Jerry的原创文章,请关注公众号"汪子熙":

  • 相关阅读:
    《观止》读后感
    读产品经理相关书籍有感
    windows phone 7基础点随手记
    Windows phone 7画图画字
    《CLR via C#》读书笔记
    《Beginning C# Objcets》学习笔记
    ASP.NET 使用alert弹出对话框后,CSS样式失效,字体变大的解决方法
    .NET COOKIE /SESSION/CACHE操作类
    【原创】VS2005 Web应用程序打包并安装数据库
    存储过程实现多条件查询
  • 原文地址:https://www.cnblogs.com/sap-jerry/p/13559349.html
Copyright © 2020-2023  润新知