软件设计不是CRUD(11):低耦合模块设计理论——业务抽象:规划模块分层

上一篇文章《软件设计不是CRUD(10):低耦合模块设计理论——业务抽象:从需求中提取业务维度》本专题详细讲解了业务抽象的一个重要步骤:提取业务维度。本篇文章内容主要讲解在提取业务维度后,如何对应用程序中初步划分的各个功能模块进行分层规划。

1、为什么要进行模块分层

需要注意的是,在对应用程序的需求进行业务维度提取时,设计人员实际上还没有,也无法对应用程序最终如何划分功能模块进行明确。这是因为提取业务维度这件事情并不以划分模块为前提,而只是业务抽象设计的第一个工作。提取业务维度所需要的业务边界,也只是从设计人员对业务理解的角度出发、从设计人员经验角度出发的大致划分。

对应用系统中初步划分的功能模块进行分层规划,将形成对初步划分的功能模块进行调整和验证的依据,以便形成更准确的模块划分和模块边界。所谓调整就是将凭直觉、凭经验进行初步划分的模块按照分层原则进行再拆分、再合并、再添加甚至进行删除。所谓验证,就是验证这些完成分层的模块是否能匹配原始的需求、是否能匹配未来可能变化的需求点。

模块分层也是保证模块间低耦合强度的前提,是明确模块间调用关系的前提。注意,这里描述的因果关系:因为满足了模块分层的基本原则,所以才能保证模块间低耦合强度。而不是一些读者理解的:因为保证了模块间的低耦合强度,所以模块自然就进行了分层。这个因果关系存在的本质原因是模块间的依赖关系可以在从设计层面上出发,不受原始业务需求限制,随意地进行依赖倒转。

2、模块分层的基本原则

以下是基于模块分层原则,完成规划的应用程序功能模块分层示意图:
在这里插入图片描述

注意:上图中所描述的各个“分层区域”不存在特定意义,只是为了便于读者对模块分层后的效果进行理解而进行的一种归纳。可以看到进行了有效的模块分层规划后,所有模块间的依赖都是单向的,并且处于同一分层区域上的两个(或多个)模块很少存在依赖关系。

原始需求对模块的分层规划具有指导性作用,但并不起决定性作用。因为模块设计和原始需求通过业务抽象进行了设计隔离。具体的效果表现为:虽然原始需求的描述中,要求A模块工作过程中需要调用B模块的功能(例如:原始需求是,出库业务完成后会调用订单模块,将当前出库单对应的订单状态变为“已完成”),但是进行模块分层规划后,B模块所处分层完全可能在A模块所处分层之上(订单模块在出库模块之上)。模块分层的主要原则有:

  • 变化风险越大的模块,分层位置越靠上
  • 模块间的依赖关系一定是单向的,且一定不存在循环依赖
  • 下层模块“看不到”上层模块
  • 上层模块可以调用、扩展下层模块的功能

2.1、业务屈服度和业务变化风险

2.1.1、业务屈服度

业务屈服度是指当一个既有功能模块的需求变化达到何种程度后,功能模块的代码就必须进行修改,否则该功能模块就不再能满足业务要求。这种“不再能满足业务要求”的变化可以由业务维度发生变化导致,也可以由功能模块的控制逻辑发生改变导致。所以也可以对以上描述做如下理解:

功能模块A之所以叫做功能模块A,是因为具有X,Y,Z这三个业务维度,并有一个固定的控制逻辑将这三个业务维度联系起来,构成一个完整的工作过程。当功能模块的业务维度需要新增,且已存在的业务维度和新的业务维度无法进行合并时;又或者当目前的控制逻辑需要做出过大调整,不能再按照原来的顺序将业务维度联系起来时,需求变化的程度就超过了功能模块可以适应变化的最大设计强度,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【lesson2】定长内存池的实现

文章目录 介绍定长内存池的设计定长内存池的实现需要成员变量需要的成员函数定长内存池结构定长内存池Delete(释放空间)的实现定长内存池New(申请空间)的实现 定长内存池的实现完整版 介绍 作为程序员(C/C)我们知道申请内存使用的…

Zookeeper实现分布式队列

目录 Zookeeper分布式队列 普通方式实现 设计思路 具体实现 使用Curator实现 具体实现 注意事项 Zookeeper分布式队列 常见的消息队列有:RabbitMQ,RocketMQ,Kafka等。Zookeeper作为一个分布式的小文件管理系统,同样能实现简单的队列功…

【python】图形化开发pyqt6基本写法模板与基础控件属性方法整理

pyqt6的简介 首先呢Python有许多可以编写图形化界面的库,我们通常跟着教程的话最初会接触的tkinter,但是学习中会发现编写的图形化跟我们平常接触的软件有很大区别(简单来说就是丑)。 pyqt则是第三方库,在Python中算…

ETL怎么实现文件处理

在现代企业及各类组织的日常运作中,数据作为一种关键的信息资源,其管理和分析能力直接影响到决策效率与准确性。文件作为数据的主要载体,承载着从运营报告、客户记录、交易明细等各种类型的数据信息。这些海量且多样的文件数据在未经处理的情…

flask_django基于python的城市轨道交通公交线路查询系统vue

同时,随着信息社会的快速发展,城市轨道交通线路查询系统面临着越来越多的信息,因此很难获得他们对高效信息的需求,如何使用方便快捷的方式使查询者在广阔的海洋信息中查询,存储,管理和共享信息方面有效&…

C语言菜鸟入门·运算符(算数运算符,关系运算符,逻辑运算符,位运算符,赋值运算符,三目运算符)详细介绍

目录 ​编辑 1. 算术运算符 2. 关系运算符 3. 逻辑运算符 4. 位运算符 5. 赋值运算符 6. 杂项运算符 ↦ sizeof & 三元 6.1 sizeof() 6.2 &取地址运算符 6.3 * 6.4 三目运算符 7. 运算符优先级 运算符是一种告诉编译器执行…

微信小程序canvas画布如何解决在for循环绘制图像显示不全的问题

如下所示&#xff0c;在for循环中绘制图像&#xff0c;由于onload函数加载图像是异步执行&#xff0c;会导致显示不全所有图片的问题。 for(var a0;a<2;a){ var img canvas.createImage()img.src product_image[items[a]]img.onload ()>{ctx.drawImage(el,0,h,i…

MySQL入门篇(7)-数据的插入、查询、更新与删除

MySQL是一种常用的关系型数据库管理系统&#xff0c;广泛应用于各种Web应用程序开发中。本博客将介绍MySQL数据库中数据的插入、查询、更新和删除操作&#xff0c;分别用到的是SQL语句中的INSERT、SELECT、UPDATE和DELETE语句。下面将详细介绍这些操作的用法及示例。 数据的插…

ElementUI组件:Link 文字链接

Link 文字链接 点击下载learnelementuispringboot项目源码 效果图 el-link.vue页面效果图 项目里el-link.vue文件代码 <script> export default {name: el_link }</script> <!--https://element.eleme.cn/#/zh-CN/component/link --> <template>&l…

TextView的setTextSize与xml中android:textSize属性值的对应关系

android中&#xff0c;对TextView设置文本字体大小&#xff0c;是通过在layout xml中设置android:textSize的属性值实现的&#xff0c;比如设置“24sp”&#xff0c;这里的sp是一种单位&#xff0c;其他可选的单位还有px&#xff0c;dip(dp)&#xff0c;pt&#xff0c;in&#…

嵌入式学习第十四天

1.结构体&#xff08;2&#xff09;: &#xff08;1&#xff09;结构体类型定义 &#xff08;2&#xff09;结构体变量的定义 &#xff08;3&#xff09;结构体元素的访问 &#xff08;4&#xff09;结构体的存储: 内存对齐: char 按照1字节对齐 …

C# OpenCvSharp DNN Gaze Estimation 视线估计

目录 介绍 效果 模型信息 项目 代码 frmMain.cs GazeEstimation.cs 下载 C# OpenCvSharp DNN Gaze Estimation 介绍 训练源码地址&#xff1a;https://github.com/deepinsight/insightface/tree/master/reconstruction/gaze 效果 模型信息 Inputs ----------------…

打破边界:如何配置 Nginx 反向代理以实现跨源CORS访问请求支持

背景知识 了解跨源访问的知识可参见笔者之前博客 flutter开发web应用网络请求后台失败--记录遇到的跨源资源共享问题-CSDN博客 本文环境 笔者的服务器为CentOS7.9&#xff0c;配置了宝塔面板&#xff0c;同时搭建了Wordpress网站&#xff0c;希望利用Wordpress的媒体库功能…

医院安全(不良)事件报告系统源码,不良事件处理的全过程管理,实现11大类不良事件类型的报告上报、流转审批、跟踪改进及统计分析功能。

医院安全&#xff08;不良&#xff09;事件报告系统源码&#xff0c;不良事件上报系统源码&#xff0c;PHP源码 医院安全&#xff08;不良&#xff09;事件报告系统提供11大类不良事件的上报、事件审核处理、时间按分析、事件跟踪与持续改进&#xff0c;事件提醒、权限控制、外…

聊聊DoIP吧

DoIP是啥? DoIP代表"Diagnostic over Internet Protocol",即互联网诊断协议。它是一种用于在车辆诊断中进行通信的网络协议。DoIP的目标是在现代汽车中实现高效的诊断和通信。通过使用互联网协议(IP)作为通信基础,DoIP使得诊断信息能够通过网络进行传输,从而提…

React通用后台模板

一. 项目初始化 1. 创建项目 环境 npm init vite 打开package.json,参考以下各模块版本: "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^7.2.8", …

Security ❀ TCP异常报文详解

文章目录 1. TCP Out-Of-Order2. TCP Previous Segment Lost3. TCP Retransmission4. TCP Dup Ack XXX#X5. TCP Windows Update6. TCP Previous segment not captured7. 异常案例分析 TCP协议中seq和ack seq的联系&#xff1a; id4的http请求报文由客户端发向服务器&#xff0…

sqli-labs-master靶场训练笔记(1-22|新手村)

2024.1.21 level-1 &#xff08;单引号装饰&#xff09; 先根据提示建立一个get请求 在尝试使用单个单引号测试&#xff0c;成功发现语句未闭合报错 然后反手一个 order by 得到数据库共3列&#xff0c;-- 后面加字母防止浏览器吃掉 -- 操作&#xff08;有些会&#xff09…

leetcode-hot100矩阵专题

73.矩阵置零 题目链接 73. 矩阵置零 - 力扣&#xff08;LeetCode&#xff09; 解题代码 class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""mapx []…

Reactor简述

1、概念 Reactor是一个计算机编程模式,它在并发编程和网络编程中用于处理大量并发输入事件。在该模型中,一个中心调度组件(即Reactor)负责监听和分发来自多个客户端的事件到相应的处理器或回调函数。当有事件发生时,如网络连接请求、数据到达等,Reactor能够及时响应并高效…