最近和儿子一起重温《龙珠Z》,我们看到了能和超三孙悟空五五开的胖布欧,我顿时就想起了之前在 SAP 成都研究院做过的一个内部培训,提到过的胖接口(Fat Interface)的概念。
当时的培训主题之一是 Interface Segregation Principle(接口分离/隔离原则),该准则期望达到的效果是,客户类不应被强迫依赖于那些它们实际并不需要的接口。
一个接口定义的方法数量越多,其实现类越容易受制于该接口。
例如,一个客户类 A 实现了一个接口,该接口包含了客户类不需要的方法,但这些方法是其他客户类所需要的,那么当其他客户类由于某种原因,需要对接口进行修改时,这个修改也将影响客户类 A.
业界把定义了过多的方法,并且这些方法在逻辑上属于不同职责领域的接口,称之为胖接口(Fat Interface).
胖接口违背了面向对象设计中的单一职责原则(Single Responsibility Principle,SRP),该原则认为一个接口应该只有一个引起变化的原因。
胖接口的问题在于,它使得实现该接口的类,必须被迫实现一些可能与类的实际用途不相关的方法。
胖接口的出现,首先会导致复杂性增加,因为接口本身变得复杂,难以理解和维护。实现类需要同时处理多个职责,增加了代码的复杂性和错误的风险。
从代码质量层面来说,胖接口导致了代码的低内聚性。内聚性指的是一个类应该包含相关性高的方法,而胖接口可能导致实现类中出现不相关的方法,所以降低了类的内聚性。
胖接口还会导致系统出现紧耦合。实现一个胖接口的类需要实现很多方法,这可能导致不相关的类之间产生耦合。当一个类的变化需要修改多个实现类时,耦合性增加会使系统更脆弱。
通过遵循接口隔离准则,我们可以避免这种不必要的耦合,比如下图把包含了 Print,Staple,Copy 和 Fax 四个方法的胖接口 Job,拆分成了四个各自只包含一个独立方法的接口,我们将这种重构,称之为符合接口隔离原则的重构。
当时有同事问,SAP ABAP 系统里的历史遗留代码里,存在类似的胖接口吗?
我们可以动手开发一个简单的 CDS view 来获取这个问题的答案。
数据库表 SEOCLASS 存放了 ABAP 系统所有的类和接口的名称,而 SEOCOMPO 存放了 ABAP 类/接口与其所包含的方法的关联关系。通过这两张表,我们使用 count(*), 就能够很容易地统计出每个 ABAP 类/接口上定义了多少个方法。
用下面的 SQL 语句,找出系统里所有方法数超过 10 个的接口列表:
DATA: lt_int TYPE STANDARD TABLE OF Zfat_Interface. SELECT * INTO TABLE @lt_int FROM ZFAT_INTERFACE where method_count > 10 ORDER BY method_count DESCENDING.
下图是我使用的 SAP CRM 系统里,按照接口定义的方法个数,从高到低排序如下:
上榜的这些接口,绝大多数都是系统和框架实现代码,并没有 SAP 应用程序的身影。
排名第一的接口是 IFUR_NW7__ALL,上面定义了 608 个方法,这个接口和 ABAP Webdynpro 界面的渲染实现有关,于 2008 年创建,最后一次修改发生在 2020 年。
管中窥豹,可见一斑。从这些数字,我们能感受到 ABAP Webdynpro 实现框架的复杂度。然而这些复杂度对于 ABAP Webdynpro 开发人员来说是完全隐藏的。应用开发人员无需了解任何关于这些复杂框架的技术实现细节,只需要使用框架提供的界面和工具,专注于应用业务逻辑本身的编写即可。
ABAP Webdynpro 在框架实现复杂度和面向应用开发人员的易用性之间做到了完美的平衡,所以我们也看到了历史上基于这个开发框架,诞生了一个个成功的基于 B/S 架构,通过浏览器访问的 SAP 产品。