当前位置: 首页 > news >正文

ABAP设计模式之---“Tell, Don’t Ask原则”

“Tell, Don’t Ask”是一种重要的面向对象编程设计原则,它强调的是对象之间如何有效地交流和协作。


1. 什么是 Tell, Don’t Ask 原则?

这个原则的核心思想是:

“告诉一个对象该做什么,而不是询问一个对象的状态再对它作出决策。”

在这里插入图片描述

解释:
  • 问(Ask)”:当你通过直接访问某个对象的属性或调用其 getter 方法获取内部状态后,在方法外部进行逻辑处理。这实际上违反了封装性,把对象的责任分散到了外部。
  • 告诉(Tell)”:让对象本身承担它的责任,而不是让调用方替它做决定。换句话说,当需要某个功能时,直接调用对象的方法,让对象自己处理。

这种方式更符合面向对象编程的精神,使得代码更加模块化、责任分明。


2. 为什么要采用 Tell, Don’t Ask 原则?

  1. 增强封装性: 对象内部的数据和逻辑是一个整体,外部调用者不应该需要关心对象的细节。
  2. 减少耦合: 外部调用者如果不需要直接操作对象的内部状态,模块之间的依赖就会减少。
  3. 更易维护: 如果需求变更,只需修改对象内部逻辑,而外部调用者无需更改。
  4. 支持扩展: 遵循该原则的代码更容易新增功能,而不会影响现有代码。

3. 不遵循 Tell, Don’t Ask 的代码示例

我们来看一个简单的例子:一个“订单”对象,负责检查产品库存是否充足,并扣减库存。如果不遵循 Tell, Don’t Ask 原则,调用者会直接查询库存,并负责判断库存是否足够,然后再调用库存扣减操作。

反例:
CLASS zcl_product DEFINITION.PUBLIC SECTION.METHODS: get_stock RETURNING VALUE(rv_stock) TYPE i,reduce_stock IMPORTING iv_quantity TYPE i.PRIVATE SECTION.DATA: mv_stock TYPE i VALUE 100. " 假设库存为 100
ENDCLASS.CLASS zcl_product IMPLEMENTATION.METHOD get_stock.rv_stock = mv_stock.ENDMETHOD.METHOD reduce_stock.mv_stock = mv_stock - iv_quantity.WRITE: / 'Stock reduced successfully. Remaining stock:', mv_stock.ENDMETHOD.
ENDCLASS." 主程序逻辑
START-OF-SELECTION.DATA(lo_product) = NEW zcl_product( ).DATA(lv_stock) TYPE i." 获取库存并检查lv_stock = lo_product->get_stock( ).IF lv_stock >= 50. " 外部负责判断库存是否足够lo_product->reduce_stock( iv_quantity = 50 ).ELSE.WRITE: / 'Not enough stock to reduce.'.ENDIF.
存在的问题:
  1. 封装性差: get_stock 方法暴露了产品对象的内部状态(库存 mv_stock)。外部调用者需要根据这些数据做逻辑判断,这让调用者替对象承担了责任。
  2. 耦合性高: 如果库存判断逻辑发生变化(比如要增加某些额外的检查条件),需要修改调用者的代码,违反了面向对象“封装变化”的原则。

4. 遵循 Tell, Don’t Ask 的代码示例

根据 Tell, Don’t Ask 原则,我们让“产品”自己负责完成“库存检查 + 扣减库存”的逻辑,调用者只需要告诉产品“我需要从你这里减少多少库存”,具体判断过程由产品自己完成。

合规代码:
CLASS zcl_product DEFINITION.PUBLIC SECTION.METHODS: reduce_stock IMPORTING iv_quantity TYPE i.PRIVATE SECTION.DATA: mv_stock TYPE i VALUE 100. " 假设库存为 100
ENDCLASS.CLASS zcl_product IMPLEMENTATION.METHOD reduce_stock.IF mv_stock >= iv_quantity.mv_stock = mv_stock - iv_quantity.WRITE: / 'Stock reduced successfully. Remaining stock:', mv_stock.ELSE.WRITE: / 'Stock not sufficient.'.ENDIF.ENDMETHOD.
ENDCLASS." 主程序逻辑
START-OF-SELECTION.DATA(lo_product) = NEW zcl_product( )." 只需要告诉产品需要减少的库存数量lo_product->reduce_stock( iv_quantity = 50 ).

改进点分析:
  1. 封装性更强:
    • 库存数据 mv_stock 只在 zcl_product 类内部操作,不对外暴露。
    • 调用者不需要知道股票的具体值和具体检查逻辑,调用者只负责“告诉”产品要执行的动作。
  2. 低耦合:
    • 如果需要修改库存检查逻辑(比如加入更多条件),只需要修改 zcl_product->reduce_stock 的实现,不用改任何调用它的代码。
  3. 代码更简洁:
    • 主程序逻辑减少了很多判断,只需要调用方法 “告诉” 产品执行相应操作即可。

5. 更复杂的示例:通过 Tell, Don’t Ask 实现对象间协作

在实际业务中,多个对象可能需要协作。以下示例使用 “订单”和“产品”对象,在创建订单时通知产品检查并扣减库存。

代码示例(产品协作订单):
CLASS zcl_product DEFINITION.PUBLIC SECTION.METHODS: check_and_reduce_stock IMPORTING iv_quantity TYPE iRETURNING VALUE(rv_success) TYPE abap_bool.PRIVATE SECTION.DATA: mv_stock TYPE i VALUE 100.
ENDCLASS.CLASS zcl_product IMPLEMENTATION.METHOD check_and_reduce_stock.IF mv_stock >= iv_quantity.mv_stock = mv_stock - iv_quantity.WRITE: / 'Stock reduced successfully. Remaining stock:', mv_stock.rv_success = abap_true.ELSE.WRITE: / 'Stock not sufficient.'.rv_success = abap_false.ENDIF.ENDMETHOD.
ENDCLASS." 订单类
CLASS zcl_order DEFINITION.PUBLIC SECTION.METHODS: create_order IMPORTING io_product TYPE REF TO zcl_productiv_quantity TYPE i.
ENDCLASS.CLASS zcl_order IMPLEMENTATION.METHOD create_order.DATA: lv_success TYPE abap_bool." 告诉产品检查和减少库存lv_success = io_product->check_and_reduce_stock( iv_quantity = iv_quantity )." 根据结果输出订单创建情况IF lv_success = abap_true.WRITE: / 'Order created successfully.'.ELSE.WRITE: / 'Order creation failed due to insufficient stock.'.ENDIF.ENDMETHOD.
ENDCLASS." 主程序逻辑
START-OF-SELECTION.DATA(lo_product) = NEW zcl_product( ).DATA(lo_order)   = NEW zcl_order( )." 创建一个订单,直接告诉产品该怎么做lo_order->create_order( io_product = lo_product iv_quantity = 50 ).

关键点:Tell, Don’t Ask 的应用:
  1. 产品自身负责库存检查和扣减(Tell)。
    • 调用方 zcl_order 不需要关心产品内部如何检查库存。
  2. 订单类通过与产品协作完成订单创建。
    • 在订单处理过程中,直接“告诉”产品所需的操作,而不是获取产品状态后再做判断。

6. 总结

  • Tell, Don’t Ask 原则强化了面向对象中的封装性和职责分离。
  • 它让对象自己对自己的数据负责,调用者只需要告诉对象它想要完成什么工作。
  • 好处:降低耦合、增强扩展性,并使代码更易维护、更符合业务逻辑。
http://www.xdnf.cn/news/953839.html

相关文章:

  • STL 1 容器
  • 基于生态系统服务(InVEST模型)的人类活动、重大工程生态成效评估、论文写作
  • 12.找到字符串中所有字母异位词
  • Oracle查询表空间大小
  • vue的<router-link>的to里面的query和params的区别
  • pocketflow库实现guardrail
  • Nginx server_name 配置说明
  • Qt插件化编程的全面解析(QPluginLoader)
  • 微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
  • 云防火墙(安全组)配置指南:从入门到精通端口开放 (2025)
  • OCR、图像分类与目标检测
  • 雷达RCS计算中的旋转矩阵
  • 在Ubuntu上利用loongarch64交叉编译工具编译opencv4.4.0
  • 【排错】ollama报错unable to load model
  • 【知识点】第8章:程序设计方法论
  • CKA考试知识点分享(6)---PriorityClass
  • 自动化测试工具playwright中文文档-------19.评估JavaScript
  • 初版BL程序一些细节整理(碎碎念)
  • 相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
  • 无线耳机存储痛点解决方案-64Mb Quad-SPI Pseudo-SRAM CS56404L
  • 向量几何的二元性:叉乘模长与内积投影的深层联系
  • 安宝特方案丨从依赖经验到数据驱动:AR套件重构特种装备装配与质检全流程
  • SQL注入篇-sqlmap的配置和使用
  • 分布式计算框架学习笔记
  • 我的世界Java版1.21.4的Fabric模组开发教程(十二)方块状态
  • UE5 文本框自动换行
  • 苍穹外卖--缓存菜品
  • 用docker来安装部署freeswitch记录
  • “一张网,万般用”——聊聊网络虚拟化到底怎么实现的
  • 大话软工笔记—记录形式