应用软件的层次划分

2023-10-27

谈到应用程序的层次,我们平时所说的层次有两种:逻辑的层次(layer)和部署的层次(tier)。这两种层次划分的目的是不同的,因此划分方式也有一些差异,能够为应用程序带来的好处也是不同的。

逻辑层次

逻辑层次(layer)划分的最重要的目的在于调整应用程序各部分之间的依赖关系。应用程序可以看作数据和业务规则的集合,这个集合通过用户界面与用户发生交互。如果不划分层次,或者只划分最简单的层次,系统的结构就会是这样:数据库处于系统的中心地位,在此之上建立用户界面,业务规则写在用户界面里。

这样做的问题在于:数据库作为应用程序的中心是不合适的,因为数据库只负责存储数据,而不能对数据做出解释(这是业务规则的任务),而业务规则分散在非中心的位置,零散的表达在用户界面中。一旦需求改变,业务规则必须随之改变,而业务规则是分散在各处的,我们就要四处寻找业务规则,进行修改。随着应用程序规模的扩大,这是一项非常艰难的任务。

为了解决复杂的依赖关系,我们创建了业务层。典型的逻辑分层结构就是:表示层->业务层->数据层。

建立业务层的方式可以非常简单:假如我们的应用程序要进行多项业务,我们分析这些业务的流程,找出这些流程中共同的部分,提取他们作为独立的过程,这就形成了最简单的业务层。这样,不同的界面之间就可以重用业务规则的代码,从一定程度上解决了依赖关系的不合理性。这是一种基于过程的方法。但是这样的方法有两个问题:

第一:他建立在对系统中的各种业务充分了解的基础之上,要正确的分析各个业务流程的细节,否则划分的流程和提取的共同过程必然有疏漏。但是在实际的开发过程中,我们往往一开始只了解业务的整体情况,对于其细节是逐渐了解的。并且对于一些隐含的关系,需要在开发的过程中才能认识到。有时候采用的一些具体的开发技术也会影响到某些业务的实现方式,进而对其流程带来影响。这样就为过程的分析带来很大的困难。

第二:基于过程的方法受到需求变化的冲击比较大。因为这样的分析方法,在实现的时候是基于业务的过程,而不是业务的目的。当系统中有业务需要变化的时候,会影响到其他具有共同过程的业务,业务之间的依赖是比较严重的,对需求变更的适应力差。

如果采用面向对象的方式,将业务进行抽象,概括实现这些业务需要使用的手段(例如需要更新数据表、向端口发送指令、保持业务进行的状态……),为所有的业务制定一个统一的框架,由这个框架决定业务执行的策略(如何限定业务的条件、分哪些步骤、失败后是重试还是放弃、何时向用户报告业务执行的进度……),框架不加区别的处理所有的业务。用户执行一个业务的时候,我们只要相应的创建一个业务对象,将这个对象置于框架内,监视执行的进度。这样,各个业务的实现就自然的隔离起来,依赖关系比较简单。同时应付需求变更也比较容易,独立的业务发生变更,只要修改一个类,如果多个业务的执行方式都要改变,则可以从框架上想办法。

如果为这个框架添加新的机制,使他不仅能够执行业务对象,还能够负责创建和销毁业务对象,就能够带来更强大的功能。业务框架就进而成为一个业务容器。当用户希望执行一个业务的时候,我们可以要求业务容器创建这个业务对象,业务容器可以交给我们一个业务对象的代理,隐藏真实的对象的位置。实际的执行过程可能是分布式的,容器为我们管理业务对象的事务性,保存业务执行的进度,必要的时候暂停业务,条件成熟后再重新开始,业务完成以后将对象销毁……这些我们都不必关心,由容器为我们做。

优化应用程序内部的依赖关系是划分逻辑层次的一个重要目的。层次间的调用机制可以采用逐层调用,也可以跨层调用,都是比较常见的方式。层次间的依赖的方向可以从上到下,也可以从下到上,都是合理的。需要小心的是,两个层次之间不可以产生互相的依赖,否则会破坏层次结构。比如有A和B两个层次,要么A依赖B,要么B依赖A,不可以互相依赖。如果必须有层次间互相调用,则必须采用某些方法转换其中一个方向上的依赖关系(可以采用的方式诸如delegete,interface,消息,事件等等)。多个层次之间也不应该出现循环的依赖关系。

部署层次

部署层次(tier)划分的目的在于增强应用程序部署的灵活性,更大限度的利用硬件环境资源。应用软件对环境有多方面的需要,比如数据存储的模块需要服务器有较强的稳定性、容错性、较高的IO效率,事务处理模块则需要运算迅速的处理器和较大的内存,而管理终端则需要有较强的表现能力。通常很难有这样的服务器满足多方面的需要,因此我们需要将应用程序分为多个层次,部署在不同的位置。

同时,在某些应用程序中需要访问一些敏感的数据,这些数据是不允许或者不可能集中到本地的,这都要求程序在部署方面增加灵活性。

从系统性能的角度说,应用程序在部署时划分合理的层次,可以增加系统的扩展性。当现有的硬件条件不满足需要的时候,可以通过改变部署方式,提高系统的性能。

比如使用一个服务器的时候可以满足100个并发业务,当并发业务达到150的时候,可以通过增加服务器满足这个要求。这就需要应用程序使用多层次的结构,缺少必要的层次是不可能进行这样的扩展的。

再如,我们需要在一个支持20个连接的数据库上建立一个支持100个客户端的系统,这时就必须建立独立于数据库的连接保持层次。

应用程序的部署层次有一些常用的模式,比如B/S结构,C/S结构,客户端/应用服务器/数据服务器结构,都是一些常用的层次划分模式。具体采用什么样的模式要看应用程序的需要,假如应用程序需要频繁的访问客户本地资源,要求较高的效率,或者要求具有强大的离线处理功能,则采用B/S结构就是不合适的,C/S结构是一个比较好的选择。如果需要在部署配置方面比较简单,又要面对不同的客户端环境,那么B/S结构就是很好的模式。如果需要建立服务器组来平衡负载,那么应用服务器则是必不可少的。

部署层次和逻辑层次有一定的关系,比如说一个程序从逻辑上不分层次,那么在部署的时候要分为多个层次就很难了。但是这两种层次并不是必须严格一致的,比如说,采用“客户端/应用服务器/数据服务器”的部署层次,并不一定意味着客户端对应着表示层,应用服务器端对应着业务层,数据服务器就一定是数据层。不能把对应关系绝对化,这两个角度划分的层次没有严格的对应关系,他们是为了达到不同的目的而划分的。

例如:在一些软件系统中,将业务逻辑以存储过程的形式直接写在数据库中。这样的系统中,业务层与数据服务器是相对应的。这样的业务层如果处理的好,一样具有清晰简洁的逻辑,维护起来也十分方便。但是这样显然会在部署上失去灵活性。

现实的问题

很多人在软件设计中常有这样的体会:在设计一个软件体系架构的时候,为了能够简化软件系统的逻辑复杂性,经常采用的手段是将一个大的系统分为若干层次。常用的方法是:分解一个庞大系统的各个功能,将其分别部署在多个部件中,每个部件只完成单一的功能,以减弱部件的复杂程度。部件之间采用一些弱耦合方式进行通信,比如消息、TCP连接等方式。

但是实际的开发和维护过程中,却发现这样并没有减轻系统的复杂程度。部件尽管已经从物理上分离,运行在不同的线程、进程、服务器上,但是部件之间在逻辑上却有着强烈的耦合关系,部件之间的接口有着时间、空间上的复杂交错关系,调用者需要依照复杂的逻辑次序,调用被调用者的接口,保存各次调用之间的状态,深入到对方的业务过程细节中。系统的结构没有因为层次而变得简洁,反而更加的复杂。一个业务的变更会在多个层次中造成影响,变更的代价更加巨大,没有起到层次模型应有的作用。

造成这个后果的原因在于,设计者混淆了逻辑层次和部署层次之间的区别。如果以减小系统的复杂程度为目的,首要的一点是从逻辑上分开层次,让各层次对业务的处理处于不同的抽象级别。为业务行为建立合理的抽象层次,而不是简单的让各个部件执行业务的某个阶段,也不是简单的让部件甲执行ABC业务,部件乙执行XYZ业务,这是逻辑层次的关键。做到了这一点,才能减小系统的复杂程度。错误的逻辑层次划分,只能使系统变得更加复杂。而盲目的划分部署层次,则是与初始的目的毫无关系的,也只能增加复杂性。

部署层次划分的作用并不在于简化系统逻辑结构,而是增加系统对环境的适应力。

逻辑层次的设计和部署层次的设计在软件开发中经常是交织在一起进行的,他们互相制约,互相影响,有共同的特征。但是这两种层次划分方式有着本质上的不同,存在着对立的方面,需要开发者在设计的时候进行协调,这也是需要注意的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

应用软件的层次划分 的相关文章

  • 解析Exception和C#处理Exception的常用方法总结

    在 NET中 异常是指成员没有完成它的名称宣称可以完成的行动 在异常的机制中 异常和某件事情的发生频率无关 异常处理四要素包括 一个表示异常详细信息的类类型 一个向调用者引发异常类实例的成员 调用者的一段调用异常成员的代码块 调用者的一段处
  • 综合评价方法

    文章目录 1 综合评价概述 1 1 基本概念 1 2 综合评价问题的五个要素 1 3 综合评价方法的思路 1 4 常用综合评价方法 2 确定权重类 2 1 信息浓缩 因子分析和主成分分析 2 2 数字相对大小 层次分析法 2 3 信息量 熵
  • Linux下查看软件安装路径

    Linux下查看软件安装路径 1 查询软件安装路径 在Linux操作系统中查看软件安装路径是通过whereis 命令 如查看sshd软件的安装路径时输入命令 whereis sshd sshd usr sbin sshd usr share

随机推荐

  • [创业之路-61] :创业者(老板)与职场(经理人)的区别(身份、职责、专业技能、行为模式)

    在职场中 创业者和职场人的行为有重大的区别 职场人从打工到创业 行为方式也需要发生重大的转变 这里以职业经理人泛指所有的职场人 本文就是探讨这个差别和自己的心路感悟 一 身份不同 创业者老板 自己独自成立或者和别人一起成立一家公司 其通过公
  • GAME Kit开发记录

    2D Game Kit开发记录 作为一款经典的2D游戏 seeker的构成用到了很多U3D中常用的手法和操作 其中包括角色移动 攻击 不同地形的材质处理 机关的触发 敌人系统 以及UI设置等 1 建立场景 作为整个游戏的基础 场景是玩家进入
  • ES6 Module 模块

    文章目录 ES6 module模块 概述 使用 export default 和 import 方式一 导出变量 方式二 导出方法 方式三 导出对象 export 和 import 方式一 方式二 别名 导出别名 导入别名 整体别名 exp
  • [黑科技] WPS通过VB宏函数实现自编号功能

    这篇文章主要是作为李老师 算法设计与分析 助教课程中 与她交流 学到的一些基础知识 它主要是讲述Word通过宏函数设置一些操作 比如在Word全文中替换一些符号 再如对Word上角表进行编号 如果删除中间某个值 运行宏函数自动编号 对Wor
  • 小程序-页面生成为图片,点击保存和分享

    前言 在实际项目中 我们可能会遇到类似的场景 点击后生成一张banner 该banner是图片类型 格式不限 用户在该页面单击之后会生成一个有遮罩的预览 长按之后有保存和分享等操作 一 海报制作 这里我们需要使用canvas来制作banne
  • 已经有int了,为什么要用integer?

    int是JAVA八大基本数据类型 byte shor int long char boolean float double 之一 JAVA语言为八大基本数据提供了包装类 Integer对应是int类型的包装类 就是把int类型包装成Obje
  • ffmpeg基础四:RTP协议

    参考 零声学院 协议学习方法 1 协议是什么 双方约定好如何传输消息 比如视频传输协议 要告诉你这个包是h264包 还是aac音频包 这个信息一般放在协议头 对方收到网络包 可以直接在协议头部获取出这些信息 所以协议的组成一般都是 协议头
  • [Python] 过程型程序设计进阶(三):Python函数装饰器

    概念 修饰器也是一个函数 接受一个函数或方法作为其唯一的参数 并返回一个修饰后的函数或方法 作用 对函数或方法进行一次修饰和包裹 之前学习过 property修饰器 接下来学习如何自定义一个修饰器 自定义函数修饰器 自定义一个装饰器 一般是
  • Jmeter集合点技术(同步定时器)

    一 集合点简介 我们怎么实现真正的并发 并发 指的是系统中正在操作业务的用户 在Jmeter中 成为线程数 Jmeter中的各线程 用户 在进行业务操作中的顺序存储存在一定的随机性 集合点的目的 让各个线程 用户 步调一致 对系统进行加压
  • MySQL8.0连接问题总结

    MySQL8 0连接问题总结 1 驱动包版本 2 驱动类 3 连接属性 1 驱动包版本 对于8 0版本的MySQL数据库 驱动包版本也要跟上 一般使用mysql connector java 8 0 11 否则会报如下错误 Caused b
  • vue代码片段

    Place your snippets for vue here Each snippet is defined under a snippet name and has a prefix body and description The
  • new Object() 和Object.create(null)

    new Object 和Object create null const obj1 a 10 b 20 const obj2 a 10 b 20 obj1 obj2 gt gt gt false 引用类型 因为内存地址不同 const ob
  • Spring之ApplicationContext快速入门

    目录 一 概述 二 代码演示 三 BeanFactory与ApplicationContext的关系 四 BeanFactory的继承体系 五 ApplicationContext的继承体系 一 概述 ApplicationContext称
  • mfc 程序闪退_VC6 在Window10 上操作打开文件时闪退或直接退出的解决方法

    1 下载FileTool exe 并解压 2 打开VC6 0 点击File Open Workspace 选择刚解压出来的FileTool dsw 并确定 3 点击Bulid Build FileTool dll 生成FileTool dl
  • 编程求1平方+2平方+...+n平方

    题目描述 编程求1平方 2平方 n平方 输入 输入一行 只有一个整数n 1 lt n lt 200 输出 输出只有一行 这意味着末尾有一个回车符号 包括1个整数 样例 输入 5 输出 55 提示 循环语句 include
  • 浅谈Visitor访问者模式

    一 前言 什么叫访问 如果大家学过数据结构 对于这点就很清晰了 遍历就是访问的一般形式 单独读取一个元素进行相应的处理也叫作访问 读取到想要查看的内容 对其进行处理就叫作访问 那么我们平常是怎么访问的呢 基本上就是直接拿着需要访问的地址来读
  • [USACO Open08]农场周围的道路

    题目描述 约翰的 N 1 N 10 9 只奶牛要出发去探索牧场四周的土地 她们将沿着一条路走 一直走到三岔路口 可以认为所有的路口都是这样的 这时候 这一群奶牛可能会分成两群 分别沿着接下来的两条路继续走 如果她们再次走到三岔路口 那么仍有
  • linux ./ 执行run文件,如何在Ubuntu中执行.bin和.run文件

    在解释如何在Ubuntu上执行 bin和 run文件之前 让我们首先定义这些文件扩展名到底是什么 Bin档 Ubuntu中的Binary或BIN文件指的是安装软件包 其中大多数是self extracting可执行文件 用于在系统上安装软件
  • BF算法 KMP算法

    BF算法 又叫朴素算法 时间复杂度为O mn 相比KMP算法比较简单 举个例子 对于给定的主字符串 ababbcabcdabcde 和子串 abcd 我们用i和j来分别遍历两个字符串 比较两个i j 对应字符串位置的元素是否相等 如果相等则
  • 应用软件的层次划分

    谈到应用程序的层次 我们平时所说的层次有两种 逻辑的层次 layer 和部署的层次 tier 这两种层次划分的目的是不同的 因此划分方式也有一些差异 能够为应用程序带来的好处也是不同的 逻辑层次逻辑层次 layer 划分的最重要的目的在于调