likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 7

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

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

一、抽象概念

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

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

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

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

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

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

二、抽象案例

浅析表单的低代码实现

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

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

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

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

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

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

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

{
    "icon":"${xx}$",
    "title":"${xx}$",
    "type":"${xx}$",
    "length":${xx}$,
    "require":${xx}$,
    "order":${xx}$
}

由此,一个简单的表单就可以用像下面的 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类型
idint
schemajson
{
    {
        "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 有依赖关系,正向依赖。

依赖倒置案例

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

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

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

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

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

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

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

public class JuejinArticle implements Knowledge {

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

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

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

// 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. 软件的设计实现就是不断对已有事物进行分析,按照特定的思维进行归纳,通过这些归纳分析总结去应对事物变化的复杂性。

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

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