写代码这件事,迈入第七个年头才有了一些心得(第三章 抽象下篇)


写代码这件事,迈入第七个年头才有了一些心得(第三章 抽象下篇)

本篇是抽象的下篇,围绕案例展开。

一、抽象概念

眼见的自然形式会蒙蔽真实的本质,简化事物的形象,才能显露艺术的真实面目 -- [荷兰]蒙德里安

抽象是一种思维,也是一种艺术,它是现实世界与机器语言之间的桥梁。

抽象就是在特定的环境,特定的视角,特定的维度,对事物进行分析、提炼、精简、归纳、推演、概括等行为,从具体到抽象,探索事物的规律和本质。

规避细节,提炼共性, 推演归集......

抽象思维是编程中最为重要的思维,充斥着每一天的生活。

二、抽象案例

浅析表单的低代码实现

元数据是对数据的描述,元数据是对数据本身的抽象;而低代码是对代码的进一步抽象,也是站在更高的视角看问题。

下面对表单进行分析,逐步理解抽象的过程。如下所示:

原始表单 分析表单

一个表单,由多个表单组件构成。(此处的组件,可以理解为表单中的文本框等)

对一个表单控件进行简单分析,理解它的组成要素,提取它的元素。(它非常像我们拿到原型去实现一样,都是将一个生动的画面,用代码进行抽象,然后去实现一样的过程)

原数 描述
icon 小图标
title 名称,比如姓名,电话、邮箱
type 类型:比如邮箱类型、比如电话类型
length 长度
order 顺序

此时把表单控件的 "骨架" 和"血肉" 进行分离,"血肉" 用占位符表示,那么表单控件的 "骨架" 都是相似的,不同的控件用不同的占位符表示。

bash 复制代码
{
    "icon":"${xx}$",
    "title":"${xx}$",
    "type":"${xx}$",
    "length":${xx}$,
    "require":${xx}$,
    "order":${xx}$
}

由此,一个简单的表单就可以用像下面的 JSON 进行描述。

JSON 复制代码
{
    {
        "icon":"icon...",
        "title":"姓名",
        "type":"name",
        "length":120,
        "require":false,
        "order":1
    },{
        "icon":"icon...",
        "title":"电话(必填)",
        "type":"phone",
        "length":120,
        "require":true,
        "order":2
    },{
        "icon":"icon...",
        "title":"邮箱",
        "type":"email",
        "length":120,
        "require":false,
        "order":3
    },{
        "icon":"icon...",
        "title":"地址",
        "type":"address",
        "length":120,
         "require":false,
         "order":4
    }
}

比如再需要一个新表单,我会这样理解: 下图左边是样式,JSON 元数据描述如右边所示:

表单描述 控件描述

于是,所有的表单都是可以用 JSON 进行描述的。再用一张表来管理所有表单描述:

表单Id 类型
id int
schema json
JSON 复制代码
{
    {
        "icon":"icon...",
        "title":"姓名",
        "type":"name",
        "length":120,
        "require":false,
        "order":1
    },{
        "icon":"icon...",
        "title":"电话(必填)",
        "type":"phone",
        "length":120,
        "require":true,
        "order":2
    }
}

表单可以得到 schema 描述信息,那么是否通过 schema 也能得到表单呢?

前端通过拿到 JSON 数据,将控件遍历渲染就能够形成不同的表单,这就能实现相互转换了。

更进一步:

如果有一个地方能生成不同的 schema, 在另外一个地方进行渲染。 从而形成不同的表单了

一个简单的表单低代码平台:

  • 编辑态:拖拉拽形成不同的 schema 元数据
  • 运行态:通过 schema 渲染形成不同的表单

一个简单的低代码表单实现想法就有了雏形。这是一种抽象的过程。

当然实际的低代码远比这个例子复杂的多,不过,在程序的世界里,一切皆可抽象!!!

接下来通过依赖倒置谈一谈抽象在软件工程中的应用,依赖倒置也是面向对象五大原则(SOLDI)中最重要的一个原则,同时也能体现如何进行抽象。

三、抽象-依赖倒置(DIP)

如果你一直写重复的代码,那么你可能体验不到编程的快乐。

依赖倒置,是我认为进行代码抽象最关键也是最重要的一个面向对象原则。 刚入门学的那会儿,被依赖倒置这个概念搞得云里雾里的,直到我开始理解并实践它,我才知道依赖倒置是那样的精髓。

理解依赖倒置之前,先理解依赖关系。

依赖关系

一般而言,依赖关系在最终的代码里体现为类构造方法、类方法等的传入参数。与关联关系相比,依赖关系除了临时"知道"对方外、还会"使用"对方的属性或方法。从这个角度讲,被依赖的对象的改变会导致依赖对象的改变。

举一个简单例子:

A 调用 B,那么 A 对 B 有依赖关系,正向依赖。

依赖倒置案例

高层模块不应该依赖底层具体实现,应该依赖抽象,模块之间的信息传递是通过抽象进行的。对应代码即接口类/抽象类不要依赖具体实现,否则也不能进行扩展。

在编写多年代码后才慢慢有体感,如下图所示,箭头的方法发生了变化。

还是案例结合吧,逐步分析依赖倒置的乐趣。以软件工程师阅读学习稀土掘金文章开始讲解吧

Java 复制代码
public interface JuejinArticle {
   
}
// 软件工程师
public interface SoftwareEngineer {
    void learn(JuejinArticle juejinArticle)
}

软件工程依赖稀土掘金文章进行学习,按照依赖这个思路出发,程序员学习就要依赖稀土掘金的文章了。 显然这是狭隘的理解; 更极端的理解,得先有了稀土掘金文章,软件工程师才进行学习。 但实际上,没有稀土掘金,软件工程也可以通过书籍文章进行学习,甚至软件工程也可以阅读任何文字进行学习。

而软件工程师学习的是知识,文章只是知识的一种承载形式。

软件工程师也不再依赖稀土掘金文章了,而是依赖知识。而稀土掘金文章不再被软件工程师所依赖。而稀土掘金文章却需要对知识进行实现,不然软件工程师也不需要稀土掘金文章,此时系统掘金文章是依赖知识,也是依赖于软件工程师的。

Java 复制代码
public class JuejinArticle implements Knowledge {

}
// 软件工程师
public interface SoftwareEngineer {
    void learn(Knowledge knowledge)
}

现在 A 调用 B, 但是却是 B 对 A 有依赖关系。 这就是简单的依赖倒置 DIP。

而依赖倒置,将控制权进行了转换。也从另外一个角度来看,我们的代码更加灵活,更加更具扩展性了。

Java 复制代码
// csdn
public class CSDNArticle implements Knowledge {
   ........
}

// github
public class GithubArticle implements Knowledge {
   ......
}

可能软件工程师可能最终还是通过稀土掘金文章进行学习知识,但思维方式已经完全不同了。

就像在拿到原型实现功能逻辑一样,最后大家写出来的程序都能跑,甚至看不出什么价值差异点; 可能真正区别的是这些代码背后软件工程师们的思维方式。

再多啰嗦两个依赖倒置的两个场景。

场景扩展之 Spring#IOC

Spring IoCInversion of Control,控制反转),由Spring来负责控制对象的生命周期和对象间的关系。即使用方掌控控制权。是 Spring 最核心的特性。

场景扩展之 API 和 SPI

SPI:控制反转,外部去实现我的定义,我定义标准。SPI 先定义后实现。

API:依赖调用,具体实现也是由外部实现。

都是接口调用,但是对接口的拥有和身份是截然不同的。一个是定义标准,一个是遵守标准

依赖倒置小结

在程序中,通过直接依赖,还是依赖倒置并没有一个精准的判断,软件工程师对这些的理解可能也不一定相同,因此具体的实现也可能差别很大。是一种内功心法,随着变化,可能差异就会有一些变化。

很多时候不是拿着表就开始写crud; 不是说着面向对象的话,干着面向过程的活; 架构的设计会影响到软件的维护成本和生命周期。

到这里,抽象的理解到此结束,下一章,会谈一谈其他面向对象原则在写代码上这件事上的影响。

四、抽象总结

  1. 找共性,提炼本质,软件的实现过程就是抽象的过程。
  2. 框架不是细节,需要打磨,控制好粒度
  3. 软件的设计实现就是不断对已有事物进行分析,按照特定的思维进行归纳,通过这些归纳分析总结去应对事物变化的复杂性。

希望有一天你的代码像一件艺术品,被反复欣赏!

🌾 代码只是形式,抽象思维才是编程的灵魂。

相关推荐
silence25012 分钟前
深入了解 Reactor:响应式编程的利器
java·spring
weixin_SAG22 分钟前
21天掌握javaweb-->第19天:Spring Boot后端优化与部署
java·spring boot·后端
m0_7482475525 分钟前
SpringMVC跨域问题解决方案
java
Elcker26 分钟前
KOI技术-事件驱动编程(Sping后端)
java·spring·架构
GitNohup29 分钟前
Spring boot处理跨域问题
java·spring boot·跨域
Just_Paranoid40 分钟前
使用 IDE生成 Java Doc
java·开发语言·ide
西海天际蔚蓝1 小时前
递归查询全量分页数据问题
java
SomeB1oody1 小时前
【Rust自学】7.4. use关键字 Pt.2 :重导入与换国内镜像源教程
开发语言·后端·rust
新知图书1 小时前
Rust编程与项目实战-箱
开发语言·后端·rust
俎树振1 小时前
深入理解与优化Java二维数组:从定义到性能提升的全面指南
java·算法