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

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 原则强化了面向对象中的封装性和职责分离。
  • 它让对象自己对自己的数据负责,调用者只需要告诉对象它想要完成什么工作。
  • 好处:降低耦合、增强扩展性,并使代码更易维护、更符合业务逻辑。

相关文章:

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

“Tell, Don’t Ask”是一种重要的面向对象编程设计原则,它强调的是对象之间如何有效地交流和协作。 1. 什么是 Tell, Don’t Ask 原则? 这个原则的核心思想是: “告诉一个对象该做什么,而不是询问一个对象的状态再对它作出决策。…...

Oracle实用参考(13)——Oracle for Linux物理DG环境搭建(2)

13.2. Oracle for Linux物理DG环境搭建 Oracle 数据库的DataGuard技术方案,业界也称为DG,其在数据库高可用、容灾及负载分离等方面,都有着非常广泛的应用,对此,前面相关章节已做过较为详尽的讲解,此处不再赘述。 需要说明的是, DG方案又分为物理DG和逻辑DG,两者的搭建…...

CentOS 7.9安装Nginx1.24.0时报 checking for LuaJIT 2.x ... not found

Nginx1.24编译时,报LuaJIT2.x错误, configuring additional modules adding module in /www/server/nginx/src/ngx_devel_kit ngx_devel_kit was configured adding module in /www/server/nginx/src/lua_nginx_module checking for LuaJIT 2.x ... not…...

IP选择注意事项

IP选择注意事项 MTP、FTP、EFUSE、EMEMORY选择时,需要考虑以下参数,然后确定后选择IP。 容量工作电压范围温度范围擦除、烧写速度/耗时读取所有bit的时间待机功耗擦写、烧写功耗面积所需要的mask layer...

虚拟机网络不通的问题(这里以win10的问题为主,模式NAT)

当我们网关配置好了,DNS也配置好了,最后在虚拟机里还是无法访问百度的网址。 第一种情况: 我们先考虑一下,网关的IP是否和虚拟机编辑器里的IP一样不,如果不一样需要更改一下,因为我们访问百度需要从物理机…...

SOC-ESP32S3部分:30-I2S音频-麦克风扬声器驱动

飞书文档https://x509p6c8to.feishu.cn/wiki/SKZzwIRH3i7lsckUOlzcuJsdnVf I2S简介 I2S(Inter-Integrated Circuit Sound)是一种用于传输数字音频数据的通信协议,广泛应用于音频设备中。 ESP32-S3 包含 2 个 I2S 外设,通过配置…...

比较数据迁移后MySQL数据库和ClickHouse数据仓库中的表

设计一个MySQL数据库和Clickhouse数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

break 语句和 continue 语句

break语句和continue语句都具有跳转作用&#xff0c;可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...

使用 uv 工具快速部署并管理 vLLM 推理环境

uv&#xff1a;现代 Python 项目管理的高效助手 uv&#xff1a;Rust 驱动的 Python 包管理新时代 在部署大语言模型&#xff08;LLM&#xff09;推理服务时&#xff0c;vLLM 是一个备受关注的方案&#xff0c;具备高吞吐、低延迟和对 OpenAI API 的良好兼容性。为了提高部署效…...

更新 Docker 容器中的某一个文件

&#x1f504; 如何更新 Docker 容器中的某一个文件 以下是几种在 Docker 中更新单个文件的常用方法&#xff0c;适用于不同场景。 ✅ 方法一&#xff1a;使用 docker cp 拷贝文件到容器中&#xff08;最简单&#xff09; &#x1f9f0; 命令格式&#xff1a; docker cp <…...

【Linux】使用1Panel 面板让服务器定时自动执行任务

服务器就是一台24小时开机的主机&#xff0c;相比自己家中不定时开关机的主机更适合完成定时任务&#xff0c;例如下载资源、备份上传&#xff0c;或者登录某个网站执行一些操作&#xff0c;只需要编写 脚本&#xff0c;然后让服务器定时来执行这个脚本就可以。 有很多方法实现…...

Python爬虫(四):PyQuery 框架

PyQuery 框架详解与对比 BeautifulSoup 第一部分&#xff1a;PyQuery 框架介绍 1. PyQuery 是什么&#xff1f; PyQuery 是一个 Python 的 HTML/XML 解析库&#xff0c;它采用了 jQuery 的语法风格&#xff0c;让开发者能够用类似前端 jQuery 的方式处理文档解析。它的核心特…...

Excel 怎么让透视表以正常Excel表格形式显示

目录 1、创建数据透视表 2、设计 》报表布局 》以表格形式显示 3、设计 》分类汇总 》不显示分类汇总 1、创建数据透视表 2、设计 》报表布局 》以表格形式显示 3、设计 》分类汇总 》不显示分类汇总...

LINUX编译vlc

下载 VideoLAN / VLC GitLab 选择最新的发布版本 准备 sudo apt install -y xcb bison sudo apt install -y autopoint sudo apt install -y autoconf automake libtool编译ffmpeg LINUX FFMPEG编译汇总&#xff08;最简化&#xff09;_底部的附件列表中】: ffmpeg - lzip…...

初级程序员入门指南

初级程序员入门指南 在数字化浪潮中&#xff0c;编程已然成为极具价值的技能。对于渴望踏入程序员行列的新手而言&#xff0c;明晰入门路径与必备知识是开启征程的关键。本文将为初级程序员提供全面的入门指引。 一、明确学习方向 &#xff08;一&#xff09;编程语言抉择 编…...

WinUI3开发_使用mica效果

简介 Mica(云母)是Windows10/11上的一种现代化效果&#xff0c;是Windows10/11上所使用的Fluent Design(设计语言)里的一个效果&#xff0c;Windows10/11上所使用的Fluent Design皆旨在于打造一个人类、通用和真正感觉与 Windows 一样的设计。 WinUI3就是Windows10/11上的一个…...

Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集

目录 一、引言&#xff1a;当爬虫遭遇"地域封锁"二、背景解析&#xff1a;分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计&#xff1a;Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...

MyBatis-Plus 常用条件构造方法

1.常用条件方法 方法 说明eq等于 ne不等于 <>gt大于 >ge大于等于 >lt小于 <le小于等于 <betweenBETWEEN 值1 AND 值2notBetweenNOT BETWEEN 值1 AND 值2likeLIKE %值%notLikeNOT LIKE %值%likeLeftLIKE %值likeRightLIKE 值%isNull字段 IS NULLisNotNull字段…...

华为OD机考- 简单的自动曝光/平均像素

import java.util.Arrays; import java.util.Scanner;public class DemoTest4 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint[] arr Array…...

C/Python/Go示例 | Socket Programing与RPC

Socket Programming介绍 Computer networking这个领域围绕着两台电脑或者同一台电脑内的不同进程之间的数据传输和信息交流&#xff0c;会涉及到许多有意思的话题&#xff0c;诸如怎么确保对方能收到信息&#xff0c;怎么应对数据丢失、被污染或者顺序混乱&#xff0c;怎么提高…...

Spring是如何实现无代理对象的循环依赖

无代理对象的循环依赖 什么是循环依赖解决方案实现方式测试验证 引入代理对象的影响创建代理对象问题分析 源码见&#xff1a;mini-spring 什么是循环依赖 循环依赖是指在对象创建过程中&#xff0c;两个或多个对象相互依赖&#xff0c;导致创建过程陷入死循环。以下通过一个简…...

C++ Saucer 编写Windows桌面应用

文章目录 一、背景二、Saucer 简介核心特性典型应用场景 三、生成自己的项目四、以Win32项目方式构建Win32项目禁用最大化按钮 五、总结 一、背景 使用Saucer框架&#xff0c;开发Windows桌面应用&#xff0c;把一个html页面作为GUI设计放到Saucer里&#xff0c;隐藏掉运行时弹…...

中国政务数据安全建设细化及市场需求分析

(基于新《政务数据共享条例》及相关法规) 一、引言 近年来,中国政府高度重视数字政府建设和数据要素市场化配置改革。《政务数据共享条例》(以下简称“《共享条例》”)的发布,与《中华人民共和国数据安全法》(以下简称“《数据安全法》”)、《中华人民共和国个人信息…...

【AI News | 20250609】每日AI进展

AI Repos 1、OpenHands-Versa OpenHands-Versa 是一个通用型 AI 智能体&#xff0c;通过结合代码编辑与执行、网络搜索、多模态网络浏览和文件访问等通用工具&#xff0c;在软件工程、网络导航和工作流自动化等多个领域展现出卓越性能。它在 SWE-Bench Multimodal、GAIA 和 Th…...

轻量安全的密码管理工具Vaultwarden

一、Vaultwarden概述 Vaultwarden主要作用是提供一个自托管的密码管理器服务。它是Bitwarden密码管理器的第三方轻量版&#xff0c;由国外开发者在Bitwarden的基础上&#xff0c;采用Rust语言重写而成。 &#xff08;一&#xff09;Vaultwarden镜像的作用及特点 轻量级与高性…...

SQLSERVER-DB操作记录

在SQL Server中&#xff0c;将查询结果放入一张新表可以通过几种方法实现。 方法1&#xff1a;使用SELECT INTO语句 SELECT INTO 语句可以直接将查询结果作为一个新表创建出来。这个新表的结构&#xff08;包括列名和数据类型&#xff09;将与查询结果匹配。 SELECT * INTO 新…...

开疆智能Ethernet/IP转Modbus网关连接鸣志步进电机驱动器配置案例

在工业自动化控制系统中&#xff0c;常常会遇到不同品牌和通信协议的设备需要协同工作的情况。本案例中&#xff0c;客户现场采用了 罗克韦尔PLC&#xff0c;但需要控制的变频器仅支持 ModbusRTU 协议。为了实现PLC 对变频器的有效控制与监控&#xff0c;引入了开疆智能Etherne…...

NineData数据库DevOps功能全面支持百度智能云向量数据库 VectorDB,助力企业 AI 应用高效落地

NineData 的数据库 DevOps 解决方案已完成对百度智能云向量数据库 VectorDB 的全链路适配&#xff0c;成为国内首批提供 VectorDB 原生操作能力的服务商。此次合作聚焦 AI 开发核心场景&#xff0c;通过标准化 SQL 工作台与细粒度权限管控两大能力&#xff0c;助力企业安全高效…...

代理服务器-LVS的3种模式与调度算法

作者介绍&#xff1a;简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 我们上一章介绍了Web服务器&#xff0c;其中以Nginx为主&#xff0c;本章我们来讲解几个代理软件&#xff1a…...

ubuntu清理垃圾

windows和ubuntu 双系统&#xff0c;ubuntu 150GB&#xff0c;开发用&#xff0c;基本不装太多软件。但是磁盘基本用完。 1、查看home目录 sudo du -h -d 1 $HOME | grep -v K 上面的命令查看$HOME一级目录大小&#xff0c;发现 .cache 有26GB&#xff0c;.local 有几个GB&am…...