ABAP-OO设计模式六大原则之三( 依赖倒转原则)

1.概念: 

依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

2.依赖倒转原则用处: 

有些时候为了代码复用,一般会把常用的代码写成函数或类库。这样开发新项目时,直接用就行了。比如做项目时大多要访问数据库,所以我们就把访问数据库的代码写成了函数。每次做项目去调用这些函数。那么我们的问题来了。我们要做新项目时,发现业务逻辑的高层模块都是一样的,但客户却希望使用不同的数据库或存储住处方式,这时就出现麻烦了。我们希望能再次利用这些高层模块,但高层模块都是与低层的访问数据库绑定在一起,没办法复用这些高层模块。所以不管是高层模块和低层模块都应该依赖于抽象,具体一点就是接口或抽象类,只要接口是稳定的,那么任何一个更改都不用担心了。

3.注意事项: 

  • 高层模块不应该依赖低层模块。两个都应该依赖抽象。
  • 抽象不应该依赖结节。细节应该依赖抽象。

4.模拟场景: 

假设现在需要一个Monitor工具,去运行一些已有的APP,自动化来完成我们的工作。Monitor工具需要启动这些已有的APP,并且写下Log。

代码实现1:

REPORT yabapoodip1.

CLASS appone DEFINITION.
  PUBLIC SECTION.
    METHODS:
      start,
      exportlog.
ENDCLASS.
CLASS appone IMPLEMENTATION.
  METHOD start.
    WRITE: / '1号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '1号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS apptwo DEFINITION.
  PUBLIC SECTION.
    METHODS:
      start,
      exportlog.
ENDCLASS.
CLASS apptwo IMPLEMENTATION.
  METHOD start.
    WRITE: / '2号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '2号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS main DEFINITION.

  PUBLIC SECTION.
    METHODS:
      constructor IMPORTING iv_appnum TYPE int4,
      start,
      exportlog.

  PRIVATE SECTION.
    DATA: mv_appnumber TYPE int4,
          mo_appone    TYPE REF TO appone,
          mo_apptwo    TYPE REF TO apptwo.
ENDCLASS.

CLASS main IMPLEMENTATION.
  METHOD constructor.
    mv_appnumber = iv_appnum.
    CASE mv_appnumber.
      WHEN 1.
        mo_appone = NEW appone( ).
      WHEN 2.
        mo_apptwo = NEW apptwo( ).
      WHEN OTHERS.
    ENDCASE.
  ENDMETHOD.
  METHOD start.
    CASE mv_appnumber.
      WHEN 1.
        mo_appone->start( ).
      WHEN 2.
        mo_apptwo->start( ).
    ENDCASE.
  ENDMETHOD.

  METHOD exportlog.
    CASE mv_appnumber.
      WHEN 1.
        mo_appone->exportlog( ).
      WHEN 2.
        mo_apptwo->exportlog( ).
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  DATA(go_main) = NEW main( 1 ).
  go_main->start( ).
  go_main->exportlog( ).

  go_main = NEW main( 2 ).
  go_main->start( ).
  go_main->exportlog( ).

代码解析1:

在代码实现1中我们已经轻松实现了Monitor去运行已有APP并且写下LOG的需求。并且代码已经上线了.

春...夏...秋...冬...

春...夏...秋...冬...

春...夏...秋...冬...

就这样,三年过去了。

一天客户找上门了,公司业务扩展了,现在需要新加2个APP用Monitor自动化。这样我们就必须得改Monitor。

代码实现2:

*&---------------------------------------------------------------------*
*& Report YABAPOODIP1
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT yabapoodip1.

CLASS appone DEFINITION.
  PUBLIC SECTION.
    METHODS:
      start,
      exportlog.
ENDCLASS.
CLASS appone IMPLEMENTATION.
  METHOD start.
    WRITE: / '1号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '1号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS apptwo DEFINITION.
  PUBLIC SECTION.
    METHODS:
      start,
      exportlog.
ENDCLASS.
CLASS apptwo IMPLEMENTATION.
  METHOD start.
    WRITE: / '2号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '2号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS appthree DEFINITION.
  PUBLIC SECTION.
    METHODS:
      start,
      exportlog.
ENDCLASS.
CLASS appthree IMPLEMENTATION.
  METHOD start.
    WRITE: / '3号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '3号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS appfour DEFINITION.
  PUBLIC SECTION.
    METHODS:
      start,
      exportlog.
ENDCLASS.
CLASS appfour IMPLEMENTATION.
  METHOD start.
    WRITE: / '4号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '4号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS main DEFINITION.

  PUBLIC SECTION.
    METHODS:
      constructor IMPORTING iv_appnum TYPE int4,
      start,
      exportlog.

  PRIVATE SECTION.
    DATA: mv_appnumber TYPE int4,
          mo_appone    TYPE REF TO appone,
          mo_apptwo    TYPE REF TO apptwo,
          mo_appthree  TYPE REF TO appone,
          mo_appfour   TYPE REF TO apptwo.
ENDCLASS.

CLASS main IMPLEMENTATION.
  METHOD constructor.
    mv_appnumber = iv_appnum.
    CASE mv_appnumber.
      WHEN 1.
        mo_appone = NEW appone( ).
      WHEN 2.
        mo_apptwo = NEW apptwo( ).
      WHEN OTHERS.
    ENDCASE.
  ENDMETHOD.
  METHOD start.
    CASE mv_appnumber.
      WHEN 1.
        mo_appone->start( ).
      WHEN 2.
        mo_apptwo->start( ).
      WHEN 3.
        mo_appthree->start( ).
      WHEN 4.
        mo_appfour->start( ).
    ENDCASE.
  ENDMETHOD.

  METHOD exportlog.
    CASE mv_appnumber.
      WHEN 1.
        mo_appone->exportlog( ).
      WHEN 2.
        mo_apptwo->exportlog( ).
      WHEN 3.
        mo_appthree->exportlog( ).
      WHEN 4.
        mo_appfour->exportlog( ).
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  DATA(go_main) = NEW main( 1 ).
  go_main->start( ).
  go_main->exportlog( ).

  go_main = NEW main( 2 ).
  go_main->start( ).
  go_main->exportlog( ).

  go_main = NEW main( 3 ).
  go_main->start( ).
  go_main->exportlog( ).

  go_main = NEW main( 4 ).
  go_main->start( ).
  go_main->exportlog( ).

代码解析2:

这样会给系统添加新的相互依赖。并且随着时间和需求的推移,会有更多的APP需要用Monitor来监测,这个Monitor工具也会被越来越对的if...else或者case...when撑爆炸,而且代码随着APP越多,越难维护。最终会导致Monitor走向灭亡(下线)。

介于这种情况,可以用Monitor这个模块来生成其它的程序,使得系统能够用在需要的APP上。OOD给我们提供了一种机制来实现这种“依赖倒置”。

代码实现3: 

*&---------------------------------------------------------------------*
*& Report YABAPOODIP2
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT yabapoodip2.

INTERFACE iapp.
  METHODS:
    start,
    exportlog.
ENDINTERFACE.

CLASS appone DEFINITION.
  PUBLIC SECTION.
    INTERFACES iapp.
    ALIASES: start FOR iapp~start,
             exportlog FOR iapp~exportlog.
ENDCLASS.

CLASS appone IMPLEMENTATION.
  METHOD start.
    WRITE: / '1号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '1号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS apptwo DEFINITION.
  PUBLIC SECTION.
    INTERFACES iapp.
    ALIASES: start FOR iapp~start,
             exportlog FOR iapp~exportlog.
ENDCLASS.

CLASS apptwo IMPLEMENTATION.
  METHOD start.
    WRITE: / '2号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '2号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS appthree DEFINITION.
  PUBLIC SECTION.
    INTERFACES iapp.
    ALIASES: start FOR iapp~start,
             exportlog FOR iapp~exportlog.
ENDCLASS.

CLASS appthree IMPLEMENTATION.
  METHOD start.
    WRITE: / '3号APP开始启动'.
  ENDMETHOD.

  METHOD exportlog.
    WRITE: / '3号APP输出日志'.
  ENDMETHOD.
ENDCLASS.

CLASS main DEFINITION.
  PUBLIC SECTION.
    METHODS:
      constructor IMPORTING io_monitor TYPE REF TO iapp,
      start,
      exportlog.
  PRIVATE SECTION.
    DATA: mo_monitor TYPE REF TO iapp.
ENDCLASS.

CLASS main IMPLEMENTATION.
  METHOD constructor.
    mo_monitor = io_monitor.
  ENDMETHOD.

  METHOD start.
    mo_monitor->start( ).
  ENDMETHOD.

  METHOD exportlog.
    mo_monitor->exportlog( ).
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA(lo_appone) = NEW appone( ).

  DATA(lo_main) = NEW main( lo_appone ).
  lo_main->start( ).
  lo_main->exportlog( ).

  DATA(lo_apptwo) = NEW apptwo( ).
  lo_main = NEW main( lo_apptwo ).
  lo_main->start( ).
  lo_main->exportlog( ).

  DATA(lo_appthree) = NEW appthree( ).
  lo_main = NEW main( lo_appthree ).
  lo_main->start( ).
  lo_main->exportlog( ).

代码解析3:

现在Monitor依赖于IApp这个接口,而与具体实现的APP类没有关系,所以无论再怎么添加APP都不会影响到Monitor本身,只需要去添加一个实现IApp接口的APP类就可以了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值