ABAP核心进阶篇(120篇):继承、多态与接口(12篇)
第十篇:继承深度优化:避免层级过深的设计原则与组合替代继承的实践方案
博客标题:《继承深度优化:避免层级过深的设计原则与组合替代继承的实践方案》
博客简介:分析继承层级过深导致的代码耦合、迭代困难问题,讲解"组合优于继承"的设计思路,结合实际业务场景演示如何通过类的组合+接口实现替代深层继承结构,大幅提升代码的可维护性与扩展性。
📖 写在前面
在ABAP面向对象开发中,继承是实现代码复用的重要手段。但在实际项目中,我们经常会遇到继承层级过深的问题:
#mermaid-svg-NKrxQKQG6lI9knnx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NKrxQKQG6lI9knnx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NKrxQKQG6lI9knnx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NKrxQKQG6lI9knnx .error-icon{fill:#552222;}#mermaid-svg-NKrxQKQG6lI9knnx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NKrxQKQG6lI9knnx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NKrxQKQG6lI9knnx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NKrxQKQG6lI9knnx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NKrxQKQG6lI9knnx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NKrxQKQG6lI9knnx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NKrxQKQG6lI9knnx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NKrxQKQG6lI9knnx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NKrxQKQG6lI9knnx .marker.cross{stroke:#333333;}#mermaid-svg-NKrxQKQG6lI9knnx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NKrxQKQG6lI9knnx p{margin:0;}#mermaid-svg-NKrxQKQG6lI9knnx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NKrxQKQG6lI9knnx .cluster-label text{fill:#333;}#mermaid-svg-NKrxQKQG6lI9knnx .cluster-label span{color:#333;}#mermaid-svg-NKrxQKQG6lI9knnx .cluster-label span p{background-color:transparent;}#mermaid-svg-NKrxQKQG6lI9knnx .label text,#mermaid-svg-NKrxQKQG6lI9knnx span{fill:#333;color:#333;}#mermaid-svg-NKrxQKQG6lI9knnx .node rect,#mermaid-svg-NKrxQKQG6lI9knnx .node circle,#mermaid-svg-NKrxQKQG6lI9knnx .node ellipse,#mermaid-svg-NKrxQKQG6lI9knnx .node polygon,#mermaid-svg-NKrxQKQG6lI9knnx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NKrxQKQG6lI9knnx .rough-node .label text,#mermaid-svg-NKrxQKQG6lI9knnx .node .label text,#mermaid-svg-NKrxQKQG6lI9knnx .image-shape .label,#mermaid-svg-NKrxQKQG6lI9knnx .icon-shape .label{text-anchor:middle;}#mermaid-svg-NKrxQKQG6lI9knnx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NKrxQKQG6lI9knnx .rough-node .label,#mermaid-svg-NKrxQKQG6lI9knnx .node .label,#mermaid-svg-NKrxQKQG6lI9knnx .image-shape .label,#mermaid-svg-NKrxQKQG6lI9knnx .icon-shape .label{text-align:center;}#mermaid-svg-NKrxQKQG6lI9knnx .node.clickable{cursor:pointer;}#mermaid-svg-NKrxQKQG6lI9knnx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NKrxQKQG6lI9knnx .arrowheadPath{fill:#333333;}#mermaid-svg-NKrxQKQG6lI9knnx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NKrxQKQG6lI9knnx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NKrxQKQG6lI9knnx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NKrxQKQG6lI9knnx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NKrxQKQG6lI9knnx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NKrxQKQG6lI9knnx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NKrxQKQG6lI9knnx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NKrxQKQG6lI9knnx .cluster text{fill:#333;}#mermaid-svg-NKrxQKQG6lI9knnx .cluster span{color:#333;}#mermaid-svg-NKrxQKQG6lI9knnx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NKrxQKQG6lI9knnx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NKrxQKQG6lI9knnx rect.text{fill:none;stroke-width:0;}#mermaid-svg-NKrxQKQG6lI9knnx .icon-shape,#mermaid-svg-NKrxQKQG6lI9knnx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NKrxQKQG6lI9knnx .icon-shape p,#mermaid-svg-NKrxQKQG6lI9knnx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NKrxQKQG6lI9knnx .icon-shape .label rect,#mermaid-svg-NKrxQKQG6lI9knnx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NKrxQKQG6lI9knnx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NKrxQKQG6lI9knnx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NKrxQKQG6lI9knnx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 🔴 过深的继承链
第1层:zcl_object
第2层:zcl_business_object
第3层:zcl_document
第4层:zcl_order
第5层:zcl_purchase_order
第6层:zcl_standard_po
深层继承的典型问题:
| 问题 | 表现 | 后果 |
|---|---|---|
| 🔴 逻辑追踪困难 | 方法实现分散在6层父类中 | 调试耗时,理解成本高 |
| 🔴 修改影响面大 | 父类修改影响所有子类 | 修改风险极高 |
| 🔴 继承"遗产"过多 | 子类继承了不需要的方法 | 代码臃肿,职责不清 |
| 🔴 扩展困难 | 业务变更需调整继承结构 | 违反开闭原则 |
本文将分析继承层级过深的问题,讲解 "组合优于继承" 的设计思路,并通过实际业务场景演示如何通过组合替代继承,大幅提升代码的可维护性与扩展性。
一、继承层级过深的问题分析
1.1 一个真实的问题代码示例
abap
" ================================================================
" ❌ 继承层级过深的示例(6层继承)
" ================================================================
" 第1层:基础对象
CLASS zcl_object DEFINITION.
PUBLIC SECTION.
METHODS: initialize.
ENDCLASS.
" 第2层:业务对象
CLASS zcl_business_object DEFINITION INHERITING FROM zcl_object.
PUBLIC SECTION.
METHODS: validate.
ENDCLASS.
" 第3层:单据对象
CLASS zcl_document DEFINITION INHERITING FROM zcl_business_object.
PUBLIC SECTION.
METHODS: save.
ENDCLASS.
" 第4层:订单对象
CLASS zcl_order DEFINITION INHERITING FROM zcl_document.
PUBLIC SECTION.
METHODS: create.
ENDCLASS.
" 第5层:采购订单
CLASS zcl_purchase_order DEFINITION INHERITING FROM zcl_order.
PUBLIC SECTION.
METHODS: settle.
ENDCLASS.
" 第6层:标准采购订单
CLASS zcl_standard_po DEFINITION INHERITING FROM zcl_purchase_order.
PUBLIC SECTION.
METHODS: calculate_amount.
ENDCLASS.
" ================================================================
" ❌ 调用时,开发人员需要了解整个继承链
" ================================================================
DATA(lo_po) = NEW zcl_standard_po( ).
lo_po->initialize( ). " 来自第1层(6层之上)
lo_po->validate( ). " 来自第2层(5层之上)
lo_po->save( ). " 来自第3层(4层之上)
lo_po->create( ). " 来自第4层(3层之上)
lo_po->settle( ). " 来自第5层(2层之上)
lo_po->calculate_amount( ). " 来自第6层(自身)
1.2 深层继承的五大问题
#mermaid-svg-XBgWZhEyyLiuZF8D{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XBgWZhEyyLiuZF8D .error-icon{fill:#552222;}#mermaid-svg-XBgWZhEyyLiuZF8D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XBgWZhEyyLiuZF8D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XBgWZhEyyLiuZF8D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XBgWZhEyyLiuZF8D .marker.cross{stroke:#333333;}#mermaid-svg-XBgWZhEyyLiuZF8D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XBgWZhEyyLiuZF8D p{margin:0;}#mermaid-svg-XBgWZhEyyLiuZF8D .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XBgWZhEyyLiuZF8D .cluster-label text{fill:#333;}#mermaid-svg-XBgWZhEyyLiuZF8D .cluster-label span{color:#333;}#mermaid-svg-XBgWZhEyyLiuZF8D .cluster-label span p{background-color:transparent;}#mermaid-svg-XBgWZhEyyLiuZF8D .label text,#mermaid-svg-XBgWZhEyyLiuZF8D span{fill:#333;color:#333;}#mermaid-svg-XBgWZhEyyLiuZF8D .node rect,#mermaid-svg-XBgWZhEyyLiuZF8D .node circle,#mermaid-svg-XBgWZhEyyLiuZF8D .node ellipse,#mermaid-svg-XBgWZhEyyLiuZF8D .node polygon,#mermaid-svg-XBgWZhEyyLiuZF8D .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XBgWZhEyyLiuZF8D .rough-node .label text,#mermaid-svg-XBgWZhEyyLiuZF8D .node .label text,#mermaid-svg-XBgWZhEyyLiuZF8D .image-shape .label,#mermaid-svg-XBgWZhEyyLiuZF8D .icon-shape .label{text-anchor:middle;}#mermaid-svg-XBgWZhEyyLiuZF8D .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XBgWZhEyyLiuZF8D .rough-node .label,#mermaid-svg-XBgWZhEyyLiuZF8D .node .label,#mermaid-svg-XBgWZhEyyLiuZF8D .image-shape .label,#mermaid-svg-XBgWZhEyyLiuZF8D .icon-shape .label{text-align:center;}#mermaid-svg-XBgWZhEyyLiuZF8D .node.clickable{cursor:pointer;}#mermaid-svg-XBgWZhEyyLiuZF8D .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XBgWZhEyyLiuZF8D .arrowheadPath{fill:#333333;}#mermaid-svg-XBgWZhEyyLiuZF8D .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XBgWZhEyyLiuZF8D .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XBgWZhEyyLiuZF8D .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XBgWZhEyyLiuZF8D .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XBgWZhEyyLiuZF8D .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XBgWZhEyyLiuZF8D .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XBgWZhEyyLiuZF8D .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XBgWZhEyyLiuZF8D .cluster text{fill:#333;}#mermaid-svg-XBgWZhEyyLiuZF8D .cluster span{color:#333;}#mermaid-svg-XBgWZhEyyLiuZF8D div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XBgWZhEyyLiuZF8D .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XBgWZhEyyLiuZF8D rect.text{fill:none;stroke-width:0;}#mermaid-svg-XBgWZhEyyLiuZF8D .icon-shape,#mermaid-svg-XBgWZhEyyLiuZF8D .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XBgWZhEyyLiuZF8D .icon-shape p,#mermaid-svg-XBgWZhEyyLiuZF8D .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XBgWZhEyyLiuZF8D .icon-shape .label rect,#mermaid-svg-XBgWZhEyyLiuZF8D .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XBgWZhEyyLiuZF8D .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XBgWZhEyyLiuZF8D .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XBgWZhEyyLiuZF8D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ❌ 深层继承问题
代码耦合
逻辑追踪困难
职责不清
扩展性差
测试困难
修改父类影响所有子类
需要逐层查看父类代码
各层职责边界模糊
新增功能需修改继承结构
需测试整个继承链
二、组合优于继承的设计原则
2.1 什么是组合?
组合(Composition) 是将多个类的实例作为属性组合在一起,通过调用组合对象的方法来实现功能。
#mermaid-svg-S9pLlZQWIsc80FmR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-S9pLlZQWIsc80FmR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-S9pLlZQWIsc80FmR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-S9pLlZQWIsc80FmR .error-icon{fill:#552222;}#mermaid-svg-S9pLlZQWIsc80FmR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-S9pLlZQWIsc80FmR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-S9pLlZQWIsc80FmR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-S9pLlZQWIsc80FmR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-S9pLlZQWIsc80FmR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-S9pLlZQWIsc80FmR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-S9pLlZQWIsc80FmR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-S9pLlZQWIsc80FmR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-S9pLlZQWIsc80FmR .marker.cross{stroke:#333333;}#mermaid-svg-S9pLlZQWIsc80FmR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-S9pLlZQWIsc80FmR p{margin:0;}#mermaid-svg-S9pLlZQWIsc80FmR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-S9pLlZQWIsc80FmR .cluster-label text{fill:#333;}#mermaid-svg-S9pLlZQWIsc80FmR .cluster-label span{color:#333;}#mermaid-svg-S9pLlZQWIsc80FmR .cluster-label span p{background-color:transparent;}#mermaid-svg-S9pLlZQWIsc80FmR .label text,#mermaid-svg-S9pLlZQWIsc80FmR span{fill:#333;color:#333;}#mermaid-svg-S9pLlZQWIsc80FmR .node rect,#mermaid-svg-S9pLlZQWIsc80FmR .node circle,#mermaid-svg-S9pLlZQWIsc80FmR .node ellipse,#mermaid-svg-S9pLlZQWIsc80FmR .node polygon,#mermaid-svg-S9pLlZQWIsc80FmR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-S9pLlZQWIsc80FmR .rough-node .label text,#mermaid-svg-S9pLlZQWIsc80FmR .node .label text,#mermaid-svg-S9pLlZQWIsc80FmR .image-shape .label,#mermaid-svg-S9pLlZQWIsc80FmR .icon-shape .label{text-anchor:middle;}#mermaid-svg-S9pLlZQWIsc80FmR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-S9pLlZQWIsc80FmR .rough-node .label,#mermaid-svg-S9pLlZQWIsc80FmR .node .label,#mermaid-svg-S9pLlZQWIsc80FmR .image-shape .label,#mermaid-svg-S9pLlZQWIsc80FmR .icon-shape .label{text-align:center;}#mermaid-svg-S9pLlZQWIsc80FmR .node.clickable{cursor:pointer;}#mermaid-svg-S9pLlZQWIsc80FmR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-S9pLlZQWIsc80FmR .arrowheadPath{fill:#333333;}#mermaid-svg-S9pLlZQWIsc80FmR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-S9pLlZQWIsc80FmR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-S9pLlZQWIsc80FmR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-S9pLlZQWIsc80FmR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-S9pLlZQWIsc80FmR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-S9pLlZQWIsc80FmR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-S9pLlZQWIsc80FmR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-S9pLlZQWIsc80FmR .cluster text{fill:#333;}#mermaid-svg-S9pLlZQWIsc80FmR .cluster span{color:#333;}#mermaid-svg-S9pLlZQWIsc80FmR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-S9pLlZQWIsc80FmR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-S9pLlZQWIsc80FmR rect.text{fill:none;stroke-width:0;}#mermaid-svg-S9pLlZQWIsc80FmR .icon-shape,#mermaid-svg-S9pLlZQWIsc80FmR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-S9pLlZQWIsc80FmR .icon-shape p,#mermaid-svg-S9pLlZQWIsc80FmR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-S9pLlZQWIsc80FmR .icon-shape .label rect,#mermaid-svg-S9pLlZQWIsc80FmR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-S9pLlZQWIsc80FmR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-S9pLlZQWIsc80FmR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-S9pLlZQWIsc80FmR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ✅ 组合模式
主类
验证组件
保存组件
计算组件
审批组件
2.2 组合 vs 继承:全方位对比
| 维度 | 🔴 继承 | 🟢 组合 |
|---|---|---|
| 关系 | "is-a"(是一个) | "has-a"(有一个) |
| 耦合度 | 🔴 高(子类依赖父类) | 🟢 低(组件独立封装) |
| 灵活性 | 🔴 差(固定继承结构) | 🟢 好(灵活组合组件) |
| 扩展性 | 🔴 差(修改父类影响所有子类) | 🟢 好(新增组件不影响现有代码) |
| 职责 | 🔴 可能包含多个职责 | 🟢 每个组件职责单一 |
| 测试 | 🔴 需测试整个继承链 | 🟢 只需测试单个组件 |
2.3 组合的四种实现模式
| 模式 | 说明 | 示例 |
|---|---|---|
| 接口组合 | 通过接口引用组合对象 | DATA: validator TYPE REF TO zif_validatable |
| 构造函数注入 | 在构造函数中传入依赖 | NEW zcl_order( io_validator = ... ) |
| Setter注入 | 通过SET方法注入依赖 | lo_order->set_validator( ... ) |
| 工厂组合 | 通过工厂创建完整组合对象 | zcl_order_factory=>create( ) |
三、组合替代继承的实践方案
3.1 四步法重构流程
#mermaid-svg-IJstZapVEjKRyKFg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IJstZapVEjKRyKFg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IJstZapVEjKRyKFg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IJstZapVEjKRyKFg .error-icon{fill:#552222;}#mermaid-svg-IJstZapVEjKRyKFg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IJstZapVEjKRyKFg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IJstZapVEjKRyKFg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IJstZapVEjKRyKFg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IJstZapVEjKRyKFg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IJstZapVEjKRyKFg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IJstZapVEjKRyKFg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IJstZapVEjKRyKFg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IJstZapVEjKRyKFg .marker.cross{stroke:#333333;}#mermaid-svg-IJstZapVEjKRyKFg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IJstZapVEjKRyKFg p{margin:0;}#mermaid-svg-IJstZapVEjKRyKFg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IJstZapVEjKRyKFg .cluster-label text{fill:#333;}#mermaid-svg-IJstZapVEjKRyKFg .cluster-label span{color:#333;}#mermaid-svg-IJstZapVEjKRyKFg .cluster-label span p{background-color:transparent;}#mermaid-svg-IJstZapVEjKRyKFg .label text,#mermaid-svg-IJstZapVEjKRyKFg span{fill:#333;color:#333;}#mermaid-svg-IJstZapVEjKRyKFg .node rect,#mermaid-svg-IJstZapVEjKRyKFg .node circle,#mermaid-svg-IJstZapVEjKRyKFg .node ellipse,#mermaid-svg-IJstZapVEjKRyKFg .node polygon,#mermaid-svg-IJstZapVEjKRyKFg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IJstZapVEjKRyKFg .rough-node .label text,#mermaid-svg-IJstZapVEjKRyKFg .node .label text,#mermaid-svg-IJstZapVEjKRyKFg .image-shape .label,#mermaid-svg-IJstZapVEjKRyKFg .icon-shape .label{text-anchor:middle;}#mermaid-svg-IJstZapVEjKRyKFg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IJstZapVEjKRyKFg .rough-node .label,#mermaid-svg-IJstZapVEjKRyKFg .node .label,#mermaid-svg-IJstZapVEjKRyKFg .image-shape .label,#mermaid-svg-IJstZapVEjKRyKFg .icon-shape .label{text-align:center;}#mermaid-svg-IJstZapVEjKRyKFg .node.clickable{cursor:pointer;}#mermaid-svg-IJstZapVEjKRyKFg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IJstZapVEjKRyKFg .arrowheadPath{fill:#333333;}#mermaid-svg-IJstZapVEjKRyKFg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IJstZapVEjKRyKFg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IJstZapVEjKRyKFg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IJstZapVEjKRyKFg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IJstZapVEjKRyKFg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IJstZapVEjKRyKFg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IJstZapVEjKRyKFg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IJstZapVEjKRyKFg .cluster text{fill:#333;}#mermaid-svg-IJstZapVEjKRyKFg .cluster span{color:#333;}#mermaid-svg-IJstZapVEjKRyKFg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IJstZapVEjKRyKFg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IJstZapVEjKRyKFg rect.text{fill:none;stroke-width:0;}#mermaid-svg-IJstZapVEjKRyKFg .icon-shape,#mermaid-svg-IJstZapVEjKRyKFg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IJstZapVEjKRyKFg .icon-shape p,#mermaid-svg-IJstZapVEjKRyKFg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IJstZapVEjKRyKFg .icon-shape .label rect,#mermaid-svg-IJstZapVEjKRyKFg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IJstZapVEjKRyKFg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IJstZapVEjKRyKFg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IJstZapVEjKRyKFg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 识别可组合的能力
② 定义能力接口
③ 实现能力类
④ 组合能力到业务类
3.2 步骤一:识别可组合的能力
#mermaid-svg-6x52uBDHRA6OJWkH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6x52uBDHRA6OJWkH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6x52uBDHRA6OJWkH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6x52uBDHRA6OJWkH .error-icon{fill:#552222;}#mermaid-svg-6x52uBDHRA6OJWkH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6x52uBDHRA6OJWkH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6x52uBDHRA6OJWkH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6x52uBDHRA6OJWkH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6x52uBDHRA6OJWkH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6x52uBDHRA6OJWkH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6x52uBDHRA6OJWkH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6x52uBDHRA6OJWkH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6x52uBDHRA6OJWkH .marker.cross{stroke:#333333;}#mermaid-svg-6x52uBDHRA6OJWkH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6x52uBDHRA6OJWkH p{margin:0;}#mermaid-svg-6x52uBDHRA6OJWkH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6x52uBDHRA6OJWkH .cluster-label text{fill:#333;}#mermaid-svg-6x52uBDHRA6OJWkH .cluster-label span{color:#333;}#mermaid-svg-6x52uBDHRA6OJWkH .cluster-label span p{background-color:transparent;}#mermaid-svg-6x52uBDHRA6OJWkH .label text,#mermaid-svg-6x52uBDHRA6OJWkH span{fill:#333;color:#333;}#mermaid-svg-6x52uBDHRA6OJWkH .node rect,#mermaid-svg-6x52uBDHRA6OJWkH .node circle,#mermaid-svg-6x52uBDHRA6OJWkH .node ellipse,#mermaid-svg-6x52uBDHRA6OJWkH .node polygon,#mermaid-svg-6x52uBDHRA6OJWkH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6x52uBDHRA6OJWkH .rough-node .label text,#mermaid-svg-6x52uBDHRA6OJWkH .node .label text,#mermaid-svg-6x52uBDHRA6OJWkH .image-shape .label,#mermaid-svg-6x52uBDHRA6OJWkH .icon-shape .label{text-anchor:middle;}#mermaid-svg-6x52uBDHRA6OJWkH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6x52uBDHRA6OJWkH .rough-node .label,#mermaid-svg-6x52uBDHRA6OJWkH .node .label,#mermaid-svg-6x52uBDHRA6OJWkH .image-shape .label,#mermaid-svg-6x52uBDHRA6OJWkH .icon-shape .label{text-align:center;}#mermaid-svg-6x52uBDHRA6OJWkH .node.clickable{cursor:pointer;}#mermaid-svg-6x52uBDHRA6OJWkH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6x52uBDHRA6OJWkH .arrowheadPath{fill:#333333;}#mermaid-svg-6x52uBDHRA6OJWkH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6x52uBDHRA6OJWkH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6x52uBDHRA6OJWkH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6x52uBDHRA6OJWkH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6x52uBDHRA6OJWkH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6x52uBDHRA6OJWkH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6x52uBDHRA6OJWkH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6x52uBDHRA6OJWkH .cluster text{fill:#333;}#mermaid-svg-6x52uBDHRA6OJWkH .cluster span{color:#333;}#mermaid-svg-6x52uBDHRA6OJWkH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6x52uBDHRA6OJWkH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6x52uBDHRA6OJWkH rect.text{fill:none;stroke-width:0;}#mermaid-svg-6x52uBDHRA6OJWkH .icon-shape,#mermaid-svg-6x52uBDHRA6OJWkH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6x52uBDHRA6OJWkH .icon-shape p,#mermaid-svg-6x52uBDHRA6OJWkH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6x52uBDHRA6OJWkH .icon-shape .label rect,#mermaid-svg-6x52uBDHRA6OJWkH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6x52uBDHRA6OJWkH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6x52uBDHRA6OJWkH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6x52uBDHRA6OJWkH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 🟢 提取为独立能力
🔴 原继承链中的方法
validate()
save()
calculate()
approve()
settle()
验证能力
保存能力
计算能力
审批能力
结算能力
3.3 步骤二:定义能力接口
abap
" ================================================================
" ✅ 每个接口只定义一种能力(单一职责原则)
" ================================================================
INTERFACE zif_validatable.
METHODS: validate RETURNING VALUE(rv_valid) TYPE abap_bool.
ENDINTERFACE.
INTERFACE zif_savable.
METHODS: save.
ENDINTERFACE.
INTERFACE zif_calculable.
METHODS: calculate
IMPORTING iv_amount TYPE netwr
RETURNING VALUE(rv_result) TYPE netwr.
ENDINTERFACE.
INTERFACE zif_approvable.
METHODS: approve
IMPORTING iv_approver TYPE sy-uname.
ENDINTERFACE.
INTERFACE zif_settlement.
METHODS: settle RETURNING VALUE(rv_success) TYPE abap_bool.
ENDINTERFACE.
3.4 步骤三:实现能力类
abap
" ================================================================
" ✅ 每个能力类独立实现一种能力
" ================================================================
" 验证能力
CLASS zcl_po_validator DEFINITION.
PUBLIC SECTION.
INTERFACES: zif_validatable.
ENDCLASS.
CLASS zcl_po_validator IMPLEMENTATION.
METHOD zif_validatable~validate.
WRITE: / '✅ 采购订单验证通过'.
rv_valid = abap_true.
ENDMETHOD.
ENDCLASS.
" 保存能力
CLASS zcl_po_saver DEFINITION.
PUBLIC SECTION.
INTERFACES: zif_savable.
ENDCLASS.
CLASS zcl_po_saver IMPLEMENTATION.
METHOD zif_savable~save.
WRITE: / '💾 采购订单已保存'.
ENDMETHOD.
ENDCLASS.
" 计算能力
CLASS zcl_po_calculator DEFINITION.
PUBLIC SECTION.
INTERFACES: zif_calculable.
ENDCLASS.
CLASS zcl_po_calculator IMPLEMENTATION.
METHOD zif_calculable~calculate.
WRITE: / '🧮 采购订单计算'.
rv_result = iv_amount * 1.1. " 含10%附加费
ENDMETHOD.
ENDCLASS.
3.5 步骤四:组合能力到业务类
abap
" ================================================================
" ✅ 通过组合实现业务类("has-a"关系)
" ================================================================
CLASS zcl_purchase_order DEFINITION.
PUBLIC SECTION.
METHODS: constructor.
METHODS: process.
PRIVATE SECTION.
DATA: validator TYPE REF TO zif_validatable,
saver TYPE REF TO zif_savable,
calculator TYPE REF TO zif_calculable,
approver TYPE REF TO zif_approvable,
settlement TYPE REF TO zif_settlement.
ENDCLASS.
CLASS zcl_purchase_order IMPLEMENTATION.
METHOD constructor.
validator = NEW zcl_po_validator( ).
saver = NEW zcl_po_saver( ).
calculator = NEW zcl_po_calculator( ).
approver = NEW zcl_po_approver( ).
settlement = NEW zcl_po_settlement( ).
ENDMETHOD.
METHOD process.
" 🎯 按需调用组合的能力
IF validator->validate( ) = abap_true.
DATA(lv_total) = calculator->calculate( 10000 ).
approver->approve( 'USER01' ).
settlement->settle( ).
saver->save( ).
WRITE: / '📋 总金额:', lv_total.
ENDIF.
ENDMETHOD.
ENDCLASS.
四、组合替代继承的实际业务场景
4.1 业务需求
企业需要四种采购订单类型,每种需要不同的能力组合:
| 订单类型 | 验证 | 保存 | 计算 | 审批 | 结算 |
|---|---|---|---|---|---|
| 标准采购订单 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 紧急采购订单 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 框架采购订单 | ✅ | ✅ | ✅ | ❌ | ❌ |
| 服务采购订单 | ✅ | ✅ | ❌ | ✅ | ❌ |
4.2 传统继承方案的局限
#mermaid-svg-eaD1ezVbY3YdXo66{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eaD1ezVbY3YdXo66 .error-icon{fill:#552222;}#mermaid-svg-eaD1ezVbY3YdXo66 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eaD1ezVbY3YdXo66 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eaD1ezVbY3YdXo66 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eaD1ezVbY3YdXo66 .marker.cross{stroke:#333333;}#mermaid-svg-eaD1ezVbY3YdXo66 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eaD1ezVbY3YdXo66 p{margin:0;}#mermaid-svg-eaD1ezVbY3YdXo66 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eaD1ezVbY3YdXo66 .cluster-label text{fill:#333;}#mermaid-svg-eaD1ezVbY3YdXo66 .cluster-label span{color:#333;}#mermaid-svg-eaD1ezVbY3YdXo66 .cluster-label span p{background-color:transparent;}#mermaid-svg-eaD1ezVbY3YdXo66 .label text,#mermaid-svg-eaD1ezVbY3YdXo66 span{fill:#333;color:#333;}#mermaid-svg-eaD1ezVbY3YdXo66 .node rect,#mermaid-svg-eaD1ezVbY3YdXo66 .node circle,#mermaid-svg-eaD1ezVbY3YdXo66 .node ellipse,#mermaid-svg-eaD1ezVbY3YdXo66 .node polygon,#mermaid-svg-eaD1ezVbY3YdXo66 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eaD1ezVbY3YdXo66 .rough-node .label text,#mermaid-svg-eaD1ezVbY3YdXo66 .node .label text,#mermaid-svg-eaD1ezVbY3YdXo66 .image-shape .label,#mermaid-svg-eaD1ezVbY3YdXo66 .icon-shape .label{text-anchor:middle;}#mermaid-svg-eaD1ezVbY3YdXo66 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eaD1ezVbY3YdXo66 .rough-node .label,#mermaid-svg-eaD1ezVbY3YdXo66 .node .label,#mermaid-svg-eaD1ezVbY3YdXo66 .image-shape .label,#mermaid-svg-eaD1ezVbY3YdXo66 .icon-shape .label{text-align:center;}#mermaid-svg-eaD1ezVbY3YdXo66 .node.clickable{cursor:pointer;}#mermaid-svg-eaD1ezVbY3YdXo66 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eaD1ezVbY3YdXo66 .arrowheadPath{fill:#333333;}#mermaid-svg-eaD1ezVbY3YdXo66 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eaD1ezVbY3YdXo66 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eaD1ezVbY3YdXo66 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eaD1ezVbY3YdXo66 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eaD1ezVbY3YdXo66 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eaD1ezVbY3YdXo66 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eaD1ezVbY3YdXo66 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eaD1ezVbY3YdXo66 .cluster text{fill:#333;}#mermaid-svg-eaD1ezVbY3YdXo66 .cluster span{color:#333;}#mermaid-svg-eaD1ezVbY3YdXo66 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eaD1ezVbY3YdXo66 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eaD1ezVbY3YdXo66 rect.text{fill:none;stroke-width:0;}#mermaid-svg-eaD1ezVbY3YdXo66 .icon-shape,#mermaid-svg-eaD1ezVbY3YdXo66 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eaD1ezVbY3YdXo66 .icon-shape p,#mermaid-svg-eaD1ezVbY3YdXo66 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eaD1ezVbY3YdXo66 .icon-shape .label rect,#mermaid-svg-eaD1ezVbY3YdXo66 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eaD1ezVbY3YdXo66 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eaD1ezVbY3YdXo66 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eaD1ezVbY3YdXo66 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 🔴 继承方案(不灵活)
基础订单类
采购订单类
标准采购订单
紧急采购订单
框架采购订单
服务采购订单
⚠️ 新增能力组合时,需调整继承结构
4.3 组合方案的灵活性
#mermaid-svg-1Y3BNhXzNzONqINP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1Y3BNhXzNzONqINP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1Y3BNhXzNzONqINP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1Y3BNhXzNzONqINP .error-icon{fill:#552222;}#mermaid-svg-1Y3BNhXzNzONqINP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1Y3BNhXzNzONqINP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1Y3BNhXzNzONqINP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1Y3BNhXzNzONqINP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1Y3BNhXzNzONqINP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1Y3BNhXzNzONqINP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1Y3BNhXzNzONqINP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1Y3BNhXzNzONqINP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1Y3BNhXzNzONqINP .marker.cross{stroke:#333333;}#mermaid-svg-1Y3BNhXzNzONqINP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1Y3BNhXzNzONqINP p{margin:0;}#mermaid-svg-1Y3BNhXzNzONqINP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1Y3BNhXzNzONqINP .cluster-label text{fill:#333;}#mermaid-svg-1Y3BNhXzNzONqINP .cluster-label span{color:#333;}#mermaid-svg-1Y3BNhXzNzONqINP .cluster-label span p{background-color:transparent;}#mermaid-svg-1Y3BNhXzNzONqINP .label text,#mermaid-svg-1Y3BNhXzNzONqINP span{fill:#333;color:#333;}#mermaid-svg-1Y3BNhXzNzONqINP .node rect,#mermaid-svg-1Y3BNhXzNzONqINP .node circle,#mermaid-svg-1Y3BNhXzNzONqINP .node ellipse,#mermaid-svg-1Y3BNhXzNzONqINP .node polygon,#mermaid-svg-1Y3BNhXzNzONqINP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1Y3BNhXzNzONqINP .rough-node .label text,#mermaid-svg-1Y3BNhXzNzONqINP .node .label text,#mermaid-svg-1Y3BNhXzNzONqINP .image-shape .label,#mermaid-svg-1Y3BNhXzNzONqINP .icon-shape .label{text-anchor:middle;}#mermaid-svg-1Y3BNhXzNzONqINP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1Y3BNhXzNzONqINP .rough-node .label,#mermaid-svg-1Y3BNhXzNzONqINP .node .label,#mermaid-svg-1Y3BNhXzNzONqINP .image-shape .label,#mermaid-svg-1Y3BNhXzNzONqINP .icon-shape .label{text-align:center;}#mermaid-svg-1Y3BNhXzNzONqINP .node.clickable{cursor:pointer;}#mermaid-svg-1Y3BNhXzNzONqINP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1Y3BNhXzNzONqINP .arrowheadPath{fill:#333333;}#mermaid-svg-1Y3BNhXzNzONqINP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1Y3BNhXzNzONqINP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1Y3BNhXzNzONqINP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1Y3BNhXzNzONqINP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1Y3BNhXzNzONqINP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1Y3BNhXzNzONqINP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1Y3BNhXzNzONqINP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1Y3BNhXzNzONqINP .cluster text{fill:#333;}#mermaid-svg-1Y3BNhXzNzONqINP .cluster span{color:#333;}#mermaid-svg-1Y3BNhXzNzONqINP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1Y3BNhXzNzONqINP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1Y3BNhXzNzONqINP rect.text{fill:none;stroke-width:0;}#mermaid-svg-1Y3BNhXzNzONqINP .icon-shape,#mermaid-svg-1Y3BNhXzNzONqINP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1Y3BNhXzNzONqINP .icon-shape p,#mermaid-svg-1Y3BNhXzNzONqINP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1Y3BNhXzNzONqINP .icon-shape .label rect,#mermaid-svg-1Y3BNhXzNzONqINP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1Y3BNhXzNzONqINP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1Y3BNhXzNzONqINP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1Y3BNhXzNzONqINP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 🟢 业务类(按需组合)
标准采购订单
V+S+C+A+ST
紧急采购订单
V+S+C+A+ST
框架采购订单
V+S+C
服务采购订单
V+S+A
🔷 能力组件(独立封装)
验证器
保存器
计算器
审批器
结算器
4.4 组合方案实现
abap
" ================================================================
" ✅ 标准采购订单:组合全部能力
" ================================================================
CLASS zcl_standard_po DEFINITION.
PUBLIC SECTION.
METHODS: constructor, process.
PRIVATE SECTION.
DATA: validator, saver, calculator, approver, settlement.
ENDCLASS.
CLASS zcl_standard_po IMPLEMENTATION.
METHOD process.
validator->validate( ).
calculator->calculate( 10000 ).
approver->approve( 'USER01' ).
settlement->settle( ).
saver->save( ).
ENDMETHOD.
ENDCLASS.
" ================================================================
" ✅ 框架采购订单:只组合验证、保存、计算(无审批、结算)
" ================================================================
CLASS zcl_framework_po DEFINITION.
PUBLIC SECTION.
METHODS: constructor, process.
PRIVATE SECTION.
DATA: validator, saver, calculator.
ENDCLASS.
CLASS zcl_framework_po IMPLEMENTATION.
METHOD process.
validator->validate( ).
calculator->calculate( 50000 ).
saver->save( ).
ENDMETHOD.
ENDCLASS.
" ================================================================
" ✅ 服务采购订单:只组合验证、保存、审批(无计算、结算)
" ================================================================
CLASS zcl_service_po DEFINITION.
PUBLIC SECTION.
METHODS: constructor, process.
PRIVATE SECTION.
DATA: validator, saver, approver.
ENDCLASS.
CLASS zcl_service_po IMPLEMENTATION.
METHOD process.
validator->validate( ).
approver->approve( 'USER01' ).
saver->save( ).
ENDMETHOD.
ENDCLASS.
4.5 组合方案的优势
| 场景 | 继承方案 | 组合方案 |
|---|---|---|
| 新增订单类型 | 🔴 需调整继承结构 | 🟢 只需组合现有能力 |
| 修改验证逻辑 | 🔴 修改父类影响所有子类 | 🟢 只修改验证器类 |
| 新增"审计"能力 | 🔴 需修改所有子类 | 🟢 只需新建审计器并组合 |
| 替换实现 | 🔴 困难(需修改继承关系) | 🟢 简单(替换组件实例) |
| 单元测试 | 🔴 需测试整个继承链 | 🟢 可单独测试每个组件 |
五、继承与组合的混合使用
5.1 两者适用场景
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 表达"is-a"关系 | 🔶 继承 | 采购订单"是"一种订单 |
| 表达"has-a"关系 | 🔷 组合 | 采购订单"有"验证能力 |
| 模板方法模式 | 🔶 继承 | 固定流程骨架 |
| 能力组合 | 🔷 组合 | 灵活按需组合 |
| 代码复用 | 🔷 组合(优先) | 低耦合 |
| 强制子类实现 | 🔶 继承 | 抽象方法 |
5.2 混合使用示例
abap
" ================================================================
" 🔶 继承:表达层级关系("is-a")
" ================================================================
CLASS zcl_order DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: process ABSTRACT.
PROTECTED SECTION.
DATA: order_id TYPE ebeln.
ENDCLASS.
" ================================================================
" 🔷 组合:表达能力关系("has-a")
" ================================================================
CLASS zcl_purchase_order DEFINITION INHERITING FROM zcl_order.
PUBLIC SECTION.
METHODS: process REDEFINITION.
PRIVATE SECTION.
DATA: validator TYPE REF TO zif_validatable,
saver TYPE REF TO zif_savable.
ENDCLASS.
CLASS zcl_purchase_order IMPLEMENTATION.
METHOD process.
validator->validate( ).
saver->save( ).
ENDMETHOD.
ENDCLASS.
六、重构:继承转组合
6.1 重构五步法
#mermaid-svg-v3C5Mnhg2kc9vnld{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-v3C5Mnhg2kc9vnld .error-icon{fill:#552222;}#mermaid-svg-v3C5Mnhg2kc9vnld .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-v3C5Mnhg2kc9vnld .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-v3C5Mnhg2kc9vnld .marker{fill:#333333;stroke:#333333;}#mermaid-svg-v3C5Mnhg2kc9vnld .marker.cross{stroke:#333333;}#mermaid-svg-v3C5Mnhg2kc9vnld svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-v3C5Mnhg2kc9vnld p{margin:0;}#mermaid-svg-v3C5Mnhg2kc9vnld .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-v3C5Mnhg2kc9vnld .cluster-label text{fill:#333;}#mermaid-svg-v3C5Mnhg2kc9vnld .cluster-label span{color:#333;}#mermaid-svg-v3C5Mnhg2kc9vnld .cluster-label span p{background-color:transparent;}#mermaid-svg-v3C5Mnhg2kc9vnld .label text,#mermaid-svg-v3C5Mnhg2kc9vnld span{fill:#333;color:#333;}#mermaid-svg-v3C5Mnhg2kc9vnld .node rect,#mermaid-svg-v3C5Mnhg2kc9vnld .node circle,#mermaid-svg-v3C5Mnhg2kc9vnld .node ellipse,#mermaid-svg-v3C5Mnhg2kc9vnld .node polygon,#mermaid-svg-v3C5Mnhg2kc9vnld .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-v3C5Mnhg2kc9vnld .rough-node .label text,#mermaid-svg-v3C5Mnhg2kc9vnld .node .label text,#mermaid-svg-v3C5Mnhg2kc9vnld .image-shape .label,#mermaid-svg-v3C5Mnhg2kc9vnld .icon-shape .label{text-anchor:middle;}#mermaid-svg-v3C5Mnhg2kc9vnld .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-v3C5Mnhg2kc9vnld .rough-node .label,#mermaid-svg-v3C5Mnhg2kc9vnld .node .label,#mermaid-svg-v3C5Mnhg2kc9vnld .image-shape .label,#mermaid-svg-v3C5Mnhg2kc9vnld .icon-shape .label{text-align:center;}#mermaid-svg-v3C5Mnhg2kc9vnld .node.clickable{cursor:pointer;}#mermaid-svg-v3C5Mnhg2kc9vnld .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-v3C5Mnhg2kc9vnld .arrowheadPath{fill:#333333;}#mermaid-svg-v3C5Mnhg2kc9vnld .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-v3C5Mnhg2kc9vnld .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-v3C5Mnhg2kc9vnld .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-v3C5Mnhg2kc9vnld .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-v3C5Mnhg2kc9vnld .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-v3C5Mnhg2kc9vnld .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-v3C5Mnhg2kc9vnld .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-v3C5Mnhg2kc9vnld .cluster text{fill:#333;}#mermaid-svg-v3C5Mnhg2kc9vnld .cluster span{color:#333;}#mermaid-svg-v3C5Mnhg2kc9vnld div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-v3C5Mnhg2kc9vnld .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-v3C5Mnhg2kc9vnld rect.text{fill:none;stroke-width:0;}#mermaid-svg-v3C5Mnhg2kc9vnld .icon-shape,#mermaid-svg-v3C5Mnhg2kc9vnld .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-v3C5Mnhg2kc9vnld .icon-shape p,#mermaid-svg-v3C5Mnhg2kc9vnld .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-v3C5Mnhg2kc9vnld .icon-shape .label rect,#mermaid-svg-v3C5Mnhg2kc9vnld .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-v3C5Mnhg2kc9vnld .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-v3C5Mnhg2kc9vnld .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-v3C5Mnhg2kc9vnld :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 分析继承链
② 提取能力接口
③ 实现能力类
④ 重构子类为组合
⑤ 测试验证
6.2 重构前后对比
abap
" ================================================================
" ❌ 重构前:继承结构(6层)
" ================================================================
CLASS zcl_standard_po DEFINITION
INHERITING FROM zcl_purchase_order. " 第6层
" 继承了 validate, save, create, settle 等所有方法
" 即使只需要其中一部分,也必须继承全部
ENDCLASS.
" ================================================================
" ✅ 重构后:组合结构(1层)
" ================================================================
CLASS zcl_standard_po DEFINITION.
" 只组合需要的能力
PRIVATE SECTION.
DATA: validator TYPE REF TO zif_validatable,
saver TYPE REF TO zif_savable,
calculator TYPE REF TO zif_calculable,
approver TYPE REF TO zif_approvable,
settlement TYPE REF TO zif_settlement.
ENDCLASS.
6.3 重构效果对比
| 指标 | 重构前 | 重构后 | 改进 |
|---|---|---|---|
| 继承层级 | 6层 | 1层 | ⬇️ 83% |
| 代码耦合 | 高 | 低 | ✅ 大幅降低 |
| 新增订单类型 | 需修改继承结构 | 只需组合能力 | ✅ 更灵活 |
| 单元测试 | 需测试6层 | 测试1层+组件 | ⬇️ 测试成本 |
七、快速参考卡片
选型决策口诀
🤔 继承还是组合?记住三问:
1. 表达"is-a"还是"has-a"?
→ "is-a"用继承,"has-a"用组合
2. 层级是否超过3层?
→ 超过3层,考虑用组合重构
3. 需要灵活组合多种能力吗?
→ 需要 → 用组合 + 接口
最佳实践速查
| 原则 | 说明 |
|---|---|
| 层级限制 | 继承层级不超过3层 |
| 职责单一 | 每个类只负责一个核心职责 |
| 接口优先 | 通过接口引用组合对象 |
| 组合优先 | 优先使用组合实现能力复用 |
| 依赖注入 | 通过构造函数注入依赖 |
八、总结
#mermaid-svg-wGC1Lj6F8Ks8K112{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wGC1Lj6F8Ks8K112 .error-icon{fill:#552222;}#mermaid-svg-wGC1Lj6F8Ks8K112 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wGC1Lj6F8Ks8K112 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .marker.cross{stroke:#333333;}#mermaid-svg-wGC1Lj6F8Ks8K112 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wGC1Lj6F8Ks8K112 p{margin:0;}#mermaid-svg-wGC1Lj6F8Ks8K112 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .cluster-label text{fill:#333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .cluster-label span{color:#333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .cluster-label span p{background-color:transparent;}#mermaid-svg-wGC1Lj6F8Ks8K112 .label text,#mermaid-svg-wGC1Lj6F8Ks8K112 span{fill:#333;color:#333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .node rect,#mermaid-svg-wGC1Lj6F8Ks8K112 .node circle,#mermaid-svg-wGC1Lj6F8Ks8K112 .node ellipse,#mermaid-svg-wGC1Lj6F8Ks8K112 .node polygon,#mermaid-svg-wGC1Lj6F8Ks8K112 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wGC1Lj6F8Ks8K112 .rough-node .label text,#mermaid-svg-wGC1Lj6F8Ks8K112 .node .label text,#mermaid-svg-wGC1Lj6F8Ks8K112 .image-shape .label,#mermaid-svg-wGC1Lj6F8Ks8K112 .icon-shape .label{text-anchor:middle;}#mermaid-svg-wGC1Lj6F8Ks8K112 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wGC1Lj6F8Ks8K112 .rough-node .label,#mermaid-svg-wGC1Lj6F8Ks8K112 .node .label,#mermaid-svg-wGC1Lj6F8Ks8K112 .image-shape .label,#mermaid-svg-wGC1Lj6F8Ks8K112 .icon-shape .label{text-align:center;}#mermaid-svg-wGC1Lj6F8Ks8K112 .node.clickable{cursor:pointer;}#mermaid-svg-wGC1Lj6F8Ks8K112 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .arrowheadPath{fill:#333333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wGC1Lj6F8Ks8K112 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wGC1Lj6F8Ks8K112 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wGC1Lj6F8Ks8K112 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wGC1Lj6F8Ks8K112 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wGC1Lj6F8Ks8K112 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wGC1Lj6F8Ks8K112 .cluster text{fill:#333;}#mermaid-svg-wGC1Lj6F8Ks8K112 .cluster span{color:#333;}#mermaid-svg-wGC1Lj6F8Ks8K112 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wGC1Lj6F8Ks8K112 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wGC1Lj6F8Ks8K112 rect.text{fill:none;stroke-width:0;}#mermaid-svg-wGC1Lj6F8Ks8K112 .icon-shape,#mermaid-svg-wGC1Lj6F8Ks8K112 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wGC1Lj6F8Ks8K112 .icon-shape p,#mermaid-svg-wGC1Lj6F8Ks8K112 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wGC1Lj6F8Ks8K112 .icon-shape .label rect,#mermaid-svg-wGC1Lj6F8Ks8K112 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wGC1Lj6F8Ks8K112 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wGC1Lj6F8Ks8K112 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wGC1Lj6F8Ks8K112 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 代码复用方案
🔶 继承
🔷 组合
'is-a'关系
层级结构
模板方法
'has-a'关系
能力组合
灵活扩展
| 核心要点 | 说明 |
|---|---|
| 继承层级控制 | 不超过3层,超过考虑组合 |
| 组合优先 | 优先使用组合实现能力复用 |
| 接口结合 | 通过接口引用组合对象,便于替换 |
| 混合使用 | 继承表达层级,组合表达能力 |
| 单一职责 | 每个类/组件只负责一个核心职责 |
下一篇预告:《避坑指南:继承、多态与接口开发的10个典型错误与排查方案》
作者 :爱喝水的鱼丶
版本记录 :2026年7月
验证基准:SAP NetWeaver 7.51
💬 你在实际项目中遇到过继承层级过深的问题吗?是如何解决的?欢迎在评论区分享你的经验!