《架构整洁之道》学习笔记 Part 2 编程范式

这篇具有很好参考价值的文章主要介绍了《架构整洁之道》学习笔记 Part 2 编程范式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

计算机编程发展至今,一共只有三个编程范式:

  • 结构化编程
  • 面向对象编程
  • 函数式编程

编程范式和软件架构的关系

  • 结构化编程是各个模块的算法实现基础
  • 多态(面向对象编程)是跨越架构边界的手段
  • 函数式编程是规范和限制数据存放位置与访问权限的手段

软件架构的三大关注重点功能性组建独立性以及数据管理,和编程范式不谋而合

结构化编程

限制控制权的直接转移,禁止 goto,用 if/else/while 替代

  • Dijkstra 发现:goto 语句的某些用法会导致模块无法被递归拆分成更小的、可证明的单元,这会导致无法采用分解法将大型问题进一步拆分成更小的、可证明的部分。
  • Bohm 和 Jocopini 证明了:可以用顺序结构、分支结构、循环结构构造出任何程序
  • 测试只能证明 Bug 的存在,并不能证明不存在 Bug
  • 结构化编程范式的价值:赋于我们构建可证伪程序单元的能力。如果测试无法证伪这些函数,就可以认为这些函数足够正确
  • 在架构设计领域,功能性降解拆分仍然是最佳实践之一

面向对象编程

限制控制权的间接转移,禁用函数指针,用多态替代

什么是面向对象?
  • 数据与函数的组合?
    • o.f() 和 f(o) 没有区别
  • 对真实世界进行建模的方式?
    • 到底如何进行?为什么这么做?有什么好处?
    • 面向对象编程究竟是什么?
  • 封装、继承、多态?
    • 面向对象编程语言必须支持这三个特性
封装

把一组关联的数据和函数关联起来,外部只能看见部分函数,数据则完全不可见。

封装并不是面向对象语言特有的,C 语言也支持:

point.h

struct Point;
struct Point* makePoint(double x, double y);
double distance(struct Point *p1, struct Point *p2)

C 语言的封装是完美的封装:利用 forward declaration,Point 的数据结构、内部实现对 point.h 的使用者完全不可见。

而后来的 C++ 虽然是面向对象的编程语言,但却破坏了封装性:

point.h

class Point {
public:
    Point(double x, double y);
    double distance(const Point& p1, const Point& p2);
    
private:
    double sqrt(double x);
private:
    double x;
    double y;
};

C++ 编译器需要知道类的对象大小,因此必须在头文件中看到成员变量的定义。虽然 private 限制了使用者访问私有成员,但这样仍然暴露了类的内部实现。(C++ 的 PIMPL 惯用法可以在一定程度上缓解这个问题)

Java 和 C# 抛弃了头文件、实现分离的编程方式,进一步削弱了封装性,因为无法区分类的声明和定义。

继承

C 语言也支持继承:

namedPoint.h

struct NamedPoint;
struct NamedPoint* makeNamedPoint(double x, double y, char* name);
void setName(struct NamePoint *np, char* name);
char* getName(struct NamedPoint *np);

namedPoint.c

#include "namePoint.h"

struct NamedPoint {
    double x;
    double y;
    char* name;
};

// 或者
#include "point.h"

struct NamePoint {
    Point parent_;
    char* name;
};

// 省略其他函数实现

main.c

#include "point.h"
#include "namedPoint.h"

int main() {
    struct NamePoint* p1 = makeNamedPoint(0.0, 0.0, "origin");
    struct NamePoint* p2 = mameNamePoint(1.0, 1.0, "upperRight");
    // C 语言中的继承需要强制转换 p1、p2 的类型
    // 真正的面向对象语言一般可以自动将子类转成父类指针/引用
    distance((struct Point*)p1, (struct Point*)p2);
}

在 main.c 中,NamePoint 被当作 Point 来使用。之所以可以,是因为 NamePoint 是 Point 的超集,且共同成员的顺序一致。C++ 中也是这样实现单继承的。

多态

在面向对象语言发明之前,C 语言也支持多态。

UNIX 要求每个 IO 设备都提供 open、close、read、write、seek 这 5 个标准函数:

struct FILE {
    void (*open)(char* name, int mode);
    void (*close)();
    int (*read)();
    void (*write)(char);
    void (*seek)(long index, int mode);
};

这里的 FILE 就相当于一个接口类,不同的 IO 设备有各自的实现函数,通过设置函数指针指向不同的实现来达到多态的目的。上层的功能逻辑只依赖 FILE 结构体中的 5 个标准函数,并不关心具体的 IO 设备什么。更换 IO 设备也无需修改功能逻辑的代码,IO 只是功能逻辑的一个插件

C++ 中每个虚函数的地址都记录在一个叫 vtable 的数据结构中,带有虚函数的类会有一个隐式的、指向 vtable 的虚表指针。每次调用虚函数都会先查询 vtable,子类构造函数负责将子类虚函数地址加载到对象的 vtable 中。

多态本质上就是函数指针的一种应用。用函数指针实现多态的问题在于函数指针的危险性。依赖人为遵守一系列的约定很容易产生难以跟踪和调试的 bug。面向对象编程使得多态再不需要依赖人工遵守约定,可以更简单、更安全地实现复杂功能。面向对象编程的出现使得“插件式架构”普及开来。

此外,面向对象编程的带来的另一个重大好处是依赖反转:通过引入接口,源码的依赖关系不再受到控制流的限制,软件架构师可以轻易地更改源码的依赖关系。这也是面向对象编程范式的核心本质(关于依赖反转,后面会单独用一篇来介绍)。

回到开始的问题,面向对象到底什么?有许多不同的说法和意见,但是对于软件架构师来说,面向对象编程就是以多态为手段,控制源码依赖的能力。这种能力可以让软件架构师构建某种插件式架构,让高层策略和底层实现组件相分离,底层组件作为插件可以独立开发和部署。

函数式编程

限制赋值操作

  • 函数式编程中的变量不可变

  • 不可变性是软件架构需要考虑的重点,因为所有的并发、死锁、竞争问题都是可变变量导致的,如果变量不可变,就不会有这些问题

  • 架构设计良好的程序应该拆分成可变不可变两种组件,其中可变状态组件中的逻辑越少越好

  • 事件溯源:只存储事务记录,不存储具体状态;需要状态时,从头计算所有事务。

    • 例如银行程序只保存每次的交易记录,不保存用户余额,每次查询余额时,将全部交易记录取出累计
    • 这种模式只需要 CR (Create & Retrieve),不需要 UD (Update & Delete),没有了更新和删除操作,自然也不存在并发问题
    • 缺点:对存储和处理能力要求较高(但随着技术的发展,这方面将越来越不成问题)
    • 应用:git

总结

从 1946 年图灵写下第一行代码至今,软件编程的核心没有变:计算机程序无一例外是由顺序结构、分支结构、循环结构和间接转移这几种行为组合而成的,无可增加, 也缺一不可。

所有三个范式都是限制了编码方式,而不是增加新能力

  • 结构化编程:限制控制权的直接转移,禁止 goto,用 if/else/while 替代
  • 面向对象编程:限制控制权的间接转移,禁用函数指针,用多态替代
  • 函数式编程:限制赋值操作

三个编程范式都是在 1958 - 1968 年间提出,此后再也没有新的范式提出,未来几乎不可能再有新的范式。因为除了 goto 语句、函数指针、赋值语句之外,也没有什么可以限制的了。文章来源地址https://www.toymoban.com/news/detail-567509.html

到了这里,关于《架构整洁之道》学习笔记 Part 2 编程范式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式学习笔记 - 开源实战三(下):借助Google Guava学习三大编程范式中的函数式编程

    现在主流的编程范式主要有三种,面向过程、面向对象和函数式编程。在理论部分,已经介绍了前面两种编程范式。本章再讲讲剩下的编程范式,函数式编程。 函数式编程并非是一个很新的东西,早在 50 年前就已经出现。近几年,函数式编程越来越被人关注,出现了很多新

    2024年04月22日
    浏览(55)
  • UNIX网络编程卷一 学习笔记 第三十章 客户/服务器程序设计范式

    开发一个Unix服务器程序时,我们本书做过的进程控制: 1.迭代服务器(iterative server),它的适用情形极为有限,因为这样的服务器在完成对当前客户的服务前无法处理已等待服务的新客户。 2.并发服务器(concurrent server),为每个客户调用fork派生一个子进程。传统上大多U

    2024年02月09日
    浏览(50)
  • 《OpenCV 计算机视觉编程攻略》学习笔记(一:图像编程入门)

    参考引用 OpenCV 计算机视觉编程攻略(第3版) 说明 本书结合 C++ 和 OpenCV 3.2 全面讲解计算机视觉编程 所有代码均在 Ubuntu 系统中用 g++ 编译执行 0. 安装 OpenCV 库 在Ubuntu上安装OpenCV及使用 OpenCV 库分为多个模块 ,常见模块如下 opencv_core 模块包含库的核心功能 opencv_imgproc 模块包

    2024年02月09日
    浏览(52)
  • 机器学习笔记 - 基于Python发现最佳计算机视觉模型的神经架构搜索技术NAS

            近年来,随着深度学习技术的兴起,计算机视觉领域取得了巨大进步。事实证明,卷积神经网络 (CNN) 在图像识别任务中异常强大,但针对特定问题设计最佳架构仍然是一项具有挑战性的任务。这就是神经架构搜索(NAS)发挥作用的地方。NAS 是一种尖端技术,可以

    2024年02月14日
    浏览(46)
  • 编程语言学习笔记-架构师和工程师的区别,PHP架构师之路

    🏆作者简介,黑夜开发者,全栈领域新星创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于PHP专栏:PHP进阶实战教程。 🎉欢迎 👍点赞✍评论⭐收藏 什么是架构师

    2024年02月12日
    浏览(52)
  • 整洁架构在前端的设计思想与应用实践

    对于每个软件系统,我们都可以通过行为和架构两个维度来体现它的实际价值。 行为是指系统实现的功能特性,一般是比较紧急的,需要按时上线。架构就是指系统架构,是重要的,但是并不总是特别紧急。因此导致我们常常忽视系统的架构价值,使得系统越来越难于理解、

    2024年02月08日
    浏览(44)
  • Java开发中的分层开发和整洁架构

    maven多模块开发项目管理. 可以利用这种管理功能,实现一个项目的多层次模块开发–分层开发. 比如,当前项目HelloController依赖HelloService 这样做目的: 复杂开发过程.解耦(不调整依赖关系,无法解耦). 分层开发(横向拆分)和纵向拆分的区别在于,拆出多层,最终运行也是一个项目. 代

    2024年02月15日
    浏览(66)
  • 【开源与项目实战:开源实战】83 | 开源实战三(下):借Google Guava学习三大编程范式中的函数式编程

    现在主流的编程范式主要有三种,面向过程、面向对象和函数式编程。在理论部分,我们已经详细讲过前两种了。今天,我们再借机会讲讲剩下的一种,函数式编程。 函数式编程并非一个很新的东西,早在 50 多年前就已经出现了。近几年,函数式编程越来越被人关注,出现

    2024年02月11日
    浏览(46)
  • Part1:使用 TensorFlow 和 Keras 的 NeRF计算机图形学和深度学习——计算机图形学世界中相机的工作原理

    是否有一种方法可以仅从一个场景多张不同视角的照片中捕获整个3D场景? 有。 NeRF:将场景表示为用于视图合成的神经辐射场中(NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis),Mildenhall等人(2020)的论文解答了这个问题。NeRF的更简单实现赢得了 TensorFlow社区聚光

    2024年02月07日
    浏览(51)
  • Hadoop学习笔记(HDP)-Part.02 核心组件原理

    目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger Part.14 安装YARN+MR Part.15 安装HIVE Part.16 安装HBase

    2024年02月04日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包