架构整洁之道下篇(实现细节)

news2024/9/20 14:24:22

目录

1.实现细节

1.1.数据库只是实现细节

1.2.Web是实现细节

1.3.应用程序框架是实现细节

1.4.案例分析:视频销售网站

1.5.拾遗

1.5.1.按层封装

1.5.2.按功能封装

1.5.3.端口和适配器

1.5.4.按组件封装

1.5.5.组织形式和封装的区别

2.总结


1.实现细节

1.1.数据库只是实现细节

为了应对磁盘访问速度带来的限制,业界逐渐发展出了两种截然不同的系统:文件系统与关系型数据库系统。数据库终究只是在硬盘与内存之间相互传输数据的一种手段而已。

当问题涉及数据存储时,这方面的操作通常是被封装起来,隔离在业务逻辑之外的。也就是说,我们确实需要从数据存储中快速地存取数据,但这终究只是一个底层实现问题。我们完全可以在数据访问这一较低的层面上解决这个问题,而不需要让它与系统架构相关联。

1.2.Web是实现细节

GUI只是一个实现细节。而Web则是GUI的一种,所以也是一个实现细节。作为一名软件架构师,我们需要将这类细节与核心业务逻辑隔离开来。

或者说:Web只是一种I/O设备。早在20世纪60年代,我们就已经了解编写设备无关应用程序的重要性。

1.3.应用程序框架是实现细节

不要让框架污染我们的核心代码,应该依据依赖关系原则,将它们当作核心代码的插件来管理。eg:千万别在业务对象里到处写@autowired注解。业务对象应该对Spring完全不知情才对。

当然,有一些框架是避免不了使用的。比如你在用Java,那么标准类库也是不太可能避免使用的。

当我们面临框架选择时,尽量不要草率地做出决定。在全身心投入之前,应该首先看看是否可以部分地采用以增加了解。另外,请尽可能长时间地将框架留在架构边界之外,越久越好。因为谁知道呢,也许你可以不用买奶牛也能喝到牛奶。

1.4.案例分析:视频销售网站

以线上收费视频网站为例,计划向个人或者企业提供一批收费的线上教学视频。个人用户通常既是购买者又是观看者。而企业用户则不同,他们购买视频通常是用来给其他人观看的。视频作者需要负责上传视频文件、写简介、提供习题等。管理员需要负责增加新的视频播放列表,往视频播放列表里添加和删除视频,并且为各种许可类型设置价格。

系统架构设计中的第一步,是识别系统中的各种角色和用例。

 典型用例分析 

初步组件架构图

双实线代表了系统架构边界,可以看到这里将系统划分成视图、展示器、交互器、控制器和工具类这几个组件。可以很简单地将它们交付为5个.jar文件;也可以将视图和展示器放在一个.jar文件中,而将其他所有的组件合并为另一个.jar文件。动态、灵活地根据系统变更来调整部署方式。

控制流是从右向左的。输入发生在控制器端,然后输入的数据经交互器处理后交由展示器格式化出结果,最后由视图来展示这个结果。请注意,图中的箭头并不是一直从右向左的。事实上大部分的箭头都是从左向右的。这是因为该架构设计要遵守依赖关系原则。所有跨越边界的依赖关系都应该是同一个方向,而且都指向包含更高级策略的组件。

另外,还应该注意一下图中的“使用”关系(开放箭头),它和控制流方向是一致的;而“继承”关系(闭合箭头)则与之相反,它反映的是我们对开闭原则的应用,通过调整依赖关系,可以保证底层细节的变更不会影响到高层策略组件。

存在两个维度上的隔离。第一个是根据单一职责原则对所使用的系统的各个角色进行了隔离,第二个则是对依赖关系原则的应用。这两个维度的隔离都是为了将不同变更原因和不同变更速率的组件分隔开来。

1.5.拾遗

假设正在构建一个在线书店,这个例子的任务是实现一个客户查看订单状态的用例。

1.5.1.按层封装

“按层封装”即传统的水平分层架构,是最简单的。在这种常见的分层架构中,Web代码分为一层,业务逻辑分为一层,持久化是另外一层。在Java中,分层的概念通常是用包来表示的。存在问题是:很快就会发现将代码分为三大块并不够,需要进一步进行模块化。

Java类说明: 
OrdersController:Web控制器,类似Spring MVC控制器,负责处理Web请求。 
OrderService:定义订单相关业务逻辑的接口。 
OrderServiceImpl:Order服务的具体实现。 
OrdersRepository:定义如何访问订单持久信息的接口。 
JdbcOrderRepository:持久信息访问接口的实现。

1.5.2.按功能封装

按功能封装,即垂直切分,根据相关的功能、业务概念或者聚合根来切分。在常见的实现中,所有的类型都会放在一个相同的包中,以业务概念来命名。相比之前,它们都被放到了同一个Java包中,比较容易找到“查看订单”相关代码。

1.5.3.端口和适配器

我们可以创造出一个业务领域代码与具体实现细节(数据库、框架等)隔离的架构。内部区域包含了所有的领域概念,而外部区域则包含了与外界交互的部分(例如UI、数据库、第三方集成等)。这里主要的规则是,只有外部代码能依赖内部代码,反之则不能。

1.5.4.按组件封装

在按层封装结构中,OrdersController可以在某些情况下绕过了OrderService类,直接调用OrdersRepository,绕过业务逻辑层是不合理的,尤其是在业务逻辑层要控制权限的情况下。

一个架构设计原则——内容是“Web控制器永远不应该直接访问数据层”,如何执行?采用静态分析工具约束不大持久,作者个人更倾向选择能够让编译器执法的做法。

“按组件封装”是指将一个粗粒度组件相关的所有类放入一个Java包中。这就像是以一种面向服务的视角来构建软件系统,与微服务架构类似,在这里,“按组件封装”将UI与粗粒度组件分离。这种方式将“业务逻辑”与“持久化代码”合并在一起,称为“组件”。组件是部署单元。组件是系统中能够部署的最小单位,对应在Java里就是jar文件。

“按组件封装”的好处是,如果我们需要编写和订单有关的代码,只有一个位置需要修改——OrdersComponet。在这个组件中,仍然应该关注重点隔离原则,但这是组件内部问题,使用者不需要关心。

1.5.5.组织形式和封装的区别

我经常遇到的一个问题是,Java中public访问控制修饰符的滥用。从另外一个角度来看,如果我们将Java程序中的所有类型都设置为public,那么包就仅仅是一种组织形式了(类似文件夹一样的分组方式),而不是一种封装方式。

以“按层封装”为例,OrderService与OrderRepository需要public修饰符,因为包外的类需要依赖它们。然而,具体实现类(OrderServiceImpl和JdbcOrdersRepository)则可以设置更细致的访问权限(包范围内的protected)。不需要有人依赖它们,它们是具体的实现细节。

以“组件封装”为例,OrdersComponet接口有来自Controller的依赖关系,但是其他类都可以设置为包protected。Public类型越少,潜在的依赖关系就越少。现在包外代码就不能再直接使用OrdersRepository接口或者其对应的实现,我们就可以利用编译器来维护架构设计原则了。

最好能利用编译器来维护所选的系统架构设计风格,小心防范来自其他地方的耦合模式,例如数据结构。所有的实现细节都是关键的!

 带有访问修饰符的类型被虚化了

2.总结

数据库只是实现细节,Web是实现细节,应用程序框架是实现细节,应与业务逻辑解耦。

在视频销售网站示例中,系统架构设计中的第一步,是识别系统中的各种角色和用例。将系统划分成视图、展示器、交互器、控制器和工具类这几个组件。控制流是从右向左的,通过调整依赖关系,可以保证底层细节的变更不会影响到高层策略组件。

在拾遗一章,作者分别使用按层封装、按功能封装、端口和适配器和按组件封装四种方式划分了组件。由于Java中public访问控制修饰符的滥用,作者提出:最好能利用编译器来维护所选的系统架构设计风格,小心防范来自其他地方的耦合模式。

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

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

相关文章

13_Uboot移植

目录 查找NXP官方的开发板默认配置文件 编译NXP官方开发板对应的uboot 烧写验证与驱动测试 SD卡和EMMC驱动检查 LCD驱动检查 网络驱动 在U-Boot中添加自己的开发板 添加开发板默认配置文件 添加开发板对应的头文件 添加开发板对应的板级文件夹 修改mx6ull_alientek_…

Vue——状态管理库Pinia

写在前面:本文参考小满大牛的pinia专栏 一、Vuex与Pinia Vuex 和 Pinia 均是 Vue.js 的状态管理库,它们为 Vue 应用程序提供了一种集中式的、可预测的状态管理解决方案。 Vuex 是 Vue.js 官方推荐的状态管理库之一。它的核心概念包括 state、mutation…

【C++初阶】类与对象(中)之取地址及const取地址操作符重载

👦个人主页:Weraphael ✍🏻作者简介:目前学习C和算法 ✈️专栏:C航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&#x1…

架构整洁之道中篇(组件构建原则软件架构)

目录 1.组件构建原则 1.1.组件 1.2.组件聚合 1.3.组件耦合 2.软件架构 2.1.什么是软件架构? 2.2.独立性 2.3.划分边界 2.4.策略与层次 2.5.业务逻辑 2.6.尖叫的软件架构 2.7.整洁架构 2.8.层次与边界 2.9.Main组件 2.10.测试边界 2.11.整洁的嵌入式…

Edgedetect2

边缘检测,检查数据变化,用异或实现 对于 8 位矢量中的每个位,检测输入信号何时从一个时钟周期变为下一个时钟周期(检测任何边沿)。输出位应在发生 0 到 1 转换后设置周期。 以下是一些示例。为清楚起见,in…

HNU-电路与电子学-小班4

第四次小班讨论 一、题目 1、书 3-41、3-62 2、书 4-23、4-26 3、设计一个时序电路。该电路仅在连续三个或三个以上时钟期间,且两个输入信号 X1 和 X2 相同时,输出信号 Z 为 1,其余情况 Z 为 0。试做出该电路的 Mealy 机和 Moore 机状态…

Windows:设置右键用RStudio打开文件和文件夹

0. 前言 在使用RStudio写R脚本的时候总是要先打开它,再通过它打开脚本和文件夹,感觉不是很方便。由于VSCode以及其他软件都可以整合到右键菜单中打开文件或文件夹,因此就折腾了一下怎么在右键中使用RStudio打开文件,下面是效果展…

简析java JNI技术

前言 认识JNI(Java Native Interface)技术,了解Java调用本地C/C库的简单原理以及一些基本的知识点;自己编写一个自定义的JNI接口。 一、简介 JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代…

在vue3中如何使用百度地图API(详细步骤+demo示例)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、注册账号、申请成为开发者二、申请密钥AK三、在vue3.0中使用百度地图API 提示:以下是本篇文章正文内容,下面案例可供参考 一、注册账号…

htb Mailroom里容器(Debian 11)图形界面显示在本机kali上,socat,unix转发,容器里不安装xrdp

在攻击机kali(ip:10.10.14.18)上运行chisel服务端: chisel server -v -p 60080 --socks5 在靶机的虚拟机(ssh root10.10.11.209)上,执行docker exec containers_sites_1 /bin/bash,进入容器里 进入容器后,先下载kali上的socat和chisel: curl -o /bin/chisel http://10.10.14…

使用JMeter+Grafana+Influxdb搭建可视化性能测试监控平台

【背景说明】 使用jmeter进行性能测试时,工具自带的查看结果方式往往不够直观和明了,所以我们需要搭建一个可视化监控平台来完成结果监控,这里我们采用三种JMeterGrafanaInfluxdb的方法来完成平台搭建 【实现原理】 通过influxdb数据库存储…

初学用于华为鸿蒙系统(HarmonyOS)的编程开发工具HUAWEI DevEco Studio:你好,鴻蒙~

本文是6月6日博文“初学用于华为鸿蒙系统(HarmonyOS)的编程开发工具HUAWEI DevEco Studio”的续篇。 成功通过华为开发者联盟的实名认证审核后,使用远程模拟器(Remote Emulator)运行程序。 步骤如下: 菜单Tools - Device Manager: 点击设备…

Vue列表渲染

1,回顾HTML列表? 答:列表分为顺序列表ol,无序列表ul,用于在网页上以表格的形式进行数据展示,数据放在单元格之中,可以用于布局或者展示某个具体对象的信息。li表示列表的每一项。自定义列表为dl…

C++多态详解(虚函数重写、接口继承、虚函数表详解)

目录 1. 多态概念 2. 多态的定义及实现 2.1 多态的构成条件 2.2 虚函数重写 2.3 C11 override和final 2.4 重载、覆盖(重写)、隐藏(重定义)的对比 3. 抽象类 3.1 概念 3.2 接口继承和实现继承 4. 多态的原理 4.1 虚函数表 4.2…

ESP32设备驱动-VCNL4010光传感器驱动

VCNL4010光传感器驱动 文章目录 VCNL4010光传感器驱动1、VCNL4010介绍2、硬件准备3、软件准备4、驱动实现1、VCNL4010介绍 VCNL4010 专为更短的距离而设计,不超过 200 毫米(约 7.5" ) 并且根据我们的实验,我们发现它在大约 10-150 毫米的距离内效果最佳。这对于检测手…

水表远程监控系统有什么功能吗?

水表远程监控系统是通过远程传输水表数据,实现对水表的远程监控和管理的一种智能化系统。它主要具备以下功能: 1.远程抄表功能:通过远程传输技术,实现对水表的远程抄表和监控,无需人工上门抄表,节省人力成本…

ChatGPT超详细教程-提问、使用、技巧~

huChatGPT已经面世很长时间了,很多人已经开始依赖ChatGPT了,逐渐应用到自己的生活工作学习中去了,然而还有很多人嚷嚷着不好用,真的不好用的话为什么广受好评,还有很多人一直在用? 当然也有可能真的对你没…

uni-app基础

1、基本语言和开发规范 uni-app代码编写,基本语言包括js、vue、css。以及ts、scss等css预编译器。 在app端,还支持原生渲染的nvue,以及可以编译为kotlin和swift的uts。 但是,DCloud提供了使用js编写服务器代码的uniCloud云引擎…

Unity Lighting Mode

在Light中Mode设置为Mixed时,Lighting Mode(在Window->Rendering->Light->Scene)有三种选项如下图: Baked Indirect 烘焙间接光,效果最好性能最耗 混合光源照亮的动态游戏对象将接收: 实时直接光照。烘焙间接…

【iOS_锁】

文章目录 前言锁线程安全锁🔒的作用锁的种类互斥锁 自旋锁加锁原理缺点对比自旋锁的缺点互斥锁的缺点 各种锁OSSpinLock使用OSSpinLockOSSpinLock存在缺陷 互斥锁分为两种: 递归锁、非递归锁 os_unfair_lock 【非递归互斥锁】锁的修饰使用 自旋锁的优先级…