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类就可以了。
1469

被折叠的 条评论
为什么被折叠?



