多数程序员难以简单的方式开发应用?入门指南_应用小白知识

心理学中有一篇相当古老、但又非常重要的论文,题为《魔法数字七(上下浮动二):人类信息处理能力中的一些限制》。这篇文章衡量了大脑处理信息的极限,并给出了一个具体的数字:人脑可以同时容纳五到九个概念。我们当然能够把这个有趣的结论延伸到诸多领域当中,但对软件开发人员而言,下面两项含义最为重要:构造(模型、实现、设计、模式等……)越简单越好,因为其概念更易于描述。构

多数程序员难以简单的方式开发应用?入门指南

心理学中有一篇相当古老、但又非常重要的论文,题为《魔法数字七(上下浮动二):人类信息处理能力中的一些限制》。这篇文章衡量了大脑处理信息的极限,并给出了一个具体的数字:人脑可以同时容纳五到九个概念。我们当然能够把这个有趣的结论延伸到诸多领域当中,但对软件开发人员而言,下面两项含义最为重要:

多数程序员难以简单的方式开发应用?入门指南_应用小白知识

  • 构造(模型、实现、设计、模式等……)越简单越好,因为其概念更易于描述。
  • 构造良好且组合良好的抽象,应该具有较少的特殊规则与意外情况,同样是因为其概念更易于描述。

总而言之,这是一场以降低概念描述难度为目标的心理战,夺取的是珍贵的心理容纳空间。

简单构造

正如英国计算机专家 Hoare 所言:软件设计构建有两种方法,一是使其尽可能简单,从而一目了然确定其中不存在缺陷;另一种方法则是使其极为复杂,以至于看不出什么明显的缺陷。

遗憾的是,他还补充道:第一种方法其实要困难得多。

在软件开发当中,添加新的模块、新的类以及越来越多的代码是件很简单的事。这能够解决软件需要面对的更多用例,但更大的代码量所产出的结果却越来越少。正如 Jamie Zawinski 所说:每一个程序都会不断扩展,一直扩展到像人一样会收邮件、看邮件。而那些无法扩展的程序,最终会被能够扩展的程序所取代。

从本质上讲,我们一直在不断扩展程序。我们向其中添加更多模块、更多类以及更多代码,而且对于每一段代码,我们都需要确保其能够与原有代码顺畅协作,从而在这个复杂性呈指数增长的过程中继续保持进一步扩展的空间。之所以会这样作,是因为增量总是更简单的——至少在起步阶段更简单。

在另一方面,越是简单的东西开发起来就越困难。这要求开发人员考虑潜在的模式与行为,并消除一切不必要的元素。但最终,这样的思维方式能够成就更出色的成果,因为我们只需要使用极少的概念与精力,就可以描述并理解程序,确保大家专注于更多宏观目标、而非细枝末节。

检测过于复杂的构造

实际上,发现这类复杂而臃肿的构造并不困难。我们看看程序手册就能知道个大概,如果其中有专门的章节来描述结构背景之下的众多词汇,基本可以断定程序复杂度已经失控。

下面来看一个例子,即 Abstract Factory(抽象工厂)模式。为了描述其工作原理,我们需要定义很多名称:

  • AbstractFactory 接口
  • < > 活动
  • Factory1(或者 ConcreteFactory)
  • ProductA 以及 ProductBinterfaces
  • ProductA1 以及 ProductB1classes
  • new 关键字
  • Abstract Factory 类图
  • :Client 以及 factory:Factory1 序列图

之所以存在这么多名称与图类,是因为复杂性比简单性更易于实现。这也迫使程序员采用针对性过强的对象创建方式,而无法选择复用存储在某处的对象等其它可能的解决方案。通过以下方式,我们尝试降低其整体复杂性:

  • 从整体模式当中删除“Factory”名称。
  • 删除 new 关键字以及 < > 活动。

现在,该模式只关注能够返回 ProductA 或者 ProductB 实例的对象。它可以对该类进行实例化、从数据结构中获取预先构建的对象,或者从某处提取该对象——具体方法无穷无尽,但这些都不重要;真正重要的是我们的目标:开始时没有对象,结束时有了对象。现在再来看名称列表,两项操作:

  • 第一项,利用接口 ProductA 获取一个对象。
  • 第二项,利用接口 ProductB 获取一个对象。

这样,我们可以自由地将该操作放在某个类、某个结构或者是某个指针当中。在使用时,我们只需要配合必要的参数对该操作进行调用,它就会为我们提供相应的对象。

在设置中,我们可以将第一项操作设置为任何能够生成 ProductA 的形式,并将第二项操作设置为任何能够生成 ProductB 的形式。没有类图、没有序列图、没有额外的类、没有不必要的字,也没有歧义——因为我们能够对某项操作做的只有调用,将其作为参数进行传递,获取返回结果并加以存储。毕竟函数与操作在本质上就是带有参数的值。我们要如何利用接口 ProductA 获取某个对象?如何才能返回一个 ProductA?答案很简单:使用第一项操作。

构造良好的抽象

我们已经在 Abstract Factory 的修正版中描述了拥有良好构造的抽象结构。

构造良好的抽象

AbstractFactory 模式显然不是什么好抽象,因为它包含一切开发者不关心、也没必要关心的繁琐细节——例如属于抽象、必须创建对象,以及使用 new 关键字等。作为用户,我并不关心这么多细节,但这些细节就在眼前,想躲都躲不开。

相反,我只希望拥有“一项能够利用 ProductA 接口为获取对象的操作。”我只需要进行调用,它就能返回 ProductA 的结果。至于具体获取方式,我不知道、也不在乎。

组合良好的抽象

AbstractFactory 模式不是什么好抽象,因为它没有得到良好组合。看看它用到的两种方法:其一是创建 ProductA;其二是创建 ProductB。为什么要把它们放在同一个 Factory 当中?为什么不能把这两项操作分开,并让希望将二者一同使用的用户将其放进同一个元组中?A 和 B 在同一个类中,绝对不是什么良好的构造方式。我该如何组合?如果其它地方也有需要使用 ProductA 的操作怎么办?那项操作是否需要了解 AbstractFactory 中的错误链?

AbstractFactory myFactory = new Factory1();
ProductA myProduct = myFactory.createProductA();
AbstractFactory somethingDifferent = new SomethingDifferentFactory();
SomethingDifferent result = somethingDifferent.fabricate(myProduct);
return result

相反,如果拥有“一项能够利用接口 ProductA 为我获取对象的操作”,而另有一项操作要求使用 ProductA 以构造别的结果,那就可以调用第一项操作来获取 ProductA,然后再用它来执行第二项操作。在类型方面:

operation : () -> ProductA
otherOperation: ProductA -> SomethingDifferent

因此: otherOperation(operation())。完事,就这么简单。

检测组合性是否良好

遗憾的是,很难通过语义检测组合性是否良好,因为开发人员已经习惯了那些没有组合性可言的做法,因此很多人压根不知道所谓组合良好究竟是什么概念。好的组合其实能够轻松感受到,这有点像是乐高积木,每一块都能轻松与其它块匹配起来,共同搭建出规模可观的作品。

这块有个三角形尖头,我们看看哪些积木块有三角形开孔。

当具有良好的组合性时,我们不需要使用适配器(或者不会设置适配器这样的概念,因为连接机制本身非常简单)。当具有良好的组合性时,我们只需要将各部分连接起来即可构建成一个整体,而不必担心这些部分会以意想不到的方式相互作用。

其整体,就是各部分相加得出的精确总和,仅此而已。

总结

我们已经看到了 AbstractFactory 如何破坏“获取 ProductA”这样一个简单的概念:一个 Factory 即为一个 Abstract,其通过 createProductA 方法利用 new 以 < > 一个拥有 ProductA< > 的 ProductA1。

这里单是关键字与概念就多达 10 个,超出了最聪明的大脑所能轻松处理的极限。更糟糕的是,由于太过刻板,我们只能使用这项操作创建对象、而无法复用对象。这也是编程为何如此困难的原因之一:我们毫无意义地抬高了它的难度。

海计划公众号
(0)
上一篇 2020/03/24 05:44
下一篇 2020/03/24 05:44

您可能感兴趣的内容

  • Nginx入门指南菜鸟教程下载_nginx菜鸟教程下载

    简介轻量级HTTP服务器事件驱动,异步非阻塞反向代理与负载均衡高并发,低内存占用安装Nginx# Ubuntu
    apt-get install nginx
    # Centos
    yum install nginx常用命令启动nginx
    停止# 立即停止
    nginx -s stop
    # 从容停止
    nginx -s quit
    # 杀死进程
    killall nginx

    2020/03/20
  • 提升工作效率的Chrome插件推荐入门指南_插件小白入门

    推荐几个我觉得非常不错的 Chrome 插件,都是我非常常用的。PostmanPostman 是一个很强大的 API调试、Http请求的工具,当你还准备拿着记事本傻傻的去写 Form 表单的时候,你来试试 Postman,你会震惊到的。OctotreeOctotree 可以让我们在 Github 上浏览代码更加方便和优雅。OneTab很多时候,我们打开了很多

    2020/03/30
  • 苹果xsmax组装手机,二手机和翻新机的区别小白入门_IT入门教程

    小编农村娃,没啥大文化,为了好理解,全程大白话!走你~大部分人买手机情愿掏高价选择正规的手机专卖店,或者商场直营店。有很少部分人会去选择二手机,翻新机或者组装机。今天小编我就给大家分析一下二手机,翻新机,组装手机他们的区别。iphonexsmax二手机:按照字面意思理解,就是某一个人将自己使用的手机转卖给他人。购买这类手机的人相比翻新机会更多一点,因为是直接

    2020/04/03
  • Http状态码整理小白知识_码小白知识

    1开头-临时响应100 (继续) 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
    101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。2开头-成功响应200 (成功) 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。
    201 (已创建) 请求成功并且服务器创建了新的资源。
    202 (已

    Web前端 2020/03/24
  • jquery中attr()、prop()、css() 的区别小白攻略_区别小白基础

    区别.attr( ) 可以设置元素的属性(也就是给元素新增加一个原来并不存在的属性)也可以获取元素的本来就有的属性以及额外设置的属性。如果要获取的属性没有设置,那么获取到的结果是 undefined; .prop( )可以设置元素的属性(HTML固有的属性,可以给元素添加属性)也可以获取元素的固有的属性值,如果是额外设置的其他属性,则无法通过prop( )获

    2020/03/26
  • CodeZen基础知识_在线源代码转图片工具

    CodeZen基础知识 官方网址:http://codezen.rishimohan.me/ 简介描述:在线源代码转图片工具 CodeZen是一个快把源代码生成一张JPG或PNG图…

    2020/03/11
  • 深度优先遍历,广度优先遍历实现对象的深拷贝 深度优先遍历使用攻略_遍历使用教程

    深度优先遍历深度优先遍历(Depth-First-Search),是搜索算法的一种,它沿着树的深度遍历树的节点,尽可能深地搜索树的分支。当节点v的所有边都已被探寻过,将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已探寻源节点到其他所有节点为止,如果还有未被发现的节点,则选择其中一个未被发现的节点为源节点并重复以上操作,直到所有节点都被探寻完成。简单

    2020/03/29
  • Paginathing.js使用帮助一款简单的jquery前台分页插件

    Paginathing.js基础入门 官方网址:https://alfrcr.github.io/paginathing/ GitHub:https://github.com/al…

    2020/03/05
  • 详解Js加法运算符小白基础_运算符入门百科

    简介JavaScript是一门了不起的语言。我喜欢它的灵活性:只需以你喜欢的方式做事:更改变量类型,动态的向对象添加方法或属性,对不同的变量类型使用运算符等等。然而动态是要付出代价的,开发人员需要知道怎样处理对于不同操作符的类型转换:加号(+),等号(==和===),不等号(!=和!==)等等,许多运算符有自己处理类型转换的方式。加法运算符最常用的运算符:+

    2020/03/23
  • 各个版本的jquery引用地址总结,jquery cdn公共库地址总汇小白教程_CDN菜鸟教程下载

    jquery作为前端常使用的插件之一,一般我们不使用下载到本地引用,直接通过CDN 公共库来加载,由于CDN的稳定,高效性,更方便开发者的调用。一般而言CDN公共库都包含了市面上最流行的开源JavaScript库,所以我们就可以在自己的网页上直接通过script标记引用这些资源,不仅节省流量,还能提高访问速度。这篇文章就总结各个版本的jquery引用地址:以

    2020/04/06
  • dns被劫持问题需要网站监控来检测零基础入门_dns基础指南

    什么是网站劫持?举个现实中的例子,当我们按照自己的需求打开某一个网站之后却发现该网站的内容并不是原来的,而这一个过程就叫做dns劫持。今天小编告诉大家dns被劫持如何修复。建议大家平时还是使用网站监控工具,推荐iis7网站监控,可以24小时监控网站,一旦有异常,会马上发送邮件通知你。一、DNS劫持手动修改DNS1、在地址栏中输入:192.168.1.1(如果

    2020/03/29
  • vue面试时需要准备的知识点入门基础知识_面试入门教程

    前端火热的框架层出不穷,作为码农的我们,依旧需要去学习,去探索新的问题,学习新技术,其实就是为了写一手好的,自认为是高质量的代码。今天主要分享一下前端最火的框架vue,也是我比较喜欢的框架。vue上手可以说是比较轻松而且简单,如果你用过angular,react,你也会很喜欢vue。vue的核心思想依旧是:构建用户界面的渐进式框架,关注视图的变化。这也是为什

    2020/04/03
  • 关于前端数据&逻辑的思考菜鸟教程下载_前端小白攻略

    最近重构了一个项目,一个基于redux模型的react-native项目,目标是在混乱的代码中梳理出一个清晰的结构来,为了实现这个目标,首先需要对项目的结构做分层处理,将各个逻辑分离出来,这里我是基于典型的MVC模型,那么为了将现有代码重构为理想的模型,我需要做以下几步:拆分组件
    逻辑处理
    抽象、聚合数据组件化
    这是一个老生常谈的问题了,从16年起前端除了构

    2020/04/05
  • Vue组件系统基础知识教程_组件指南攻略

    vue.js既然是框架,那就不能只是简单的完成数据模板引擎的任务,它还提供了页面布局的功能。本文详细介绍使用vue.js进行页面布局的强大工具,vue.js组件系统。每一个新技术的诞生,都是为了解决特定的问题。组件的出现就是为了解决页面布局等等一系列问题。vue中的组件分为两种,全局组件和局部组件。一、全局组件的注册通过Vue.component()创建一个

    2020/03/26
  • Whoer新手入门_在线查看自己的IP信息工具

    Whoer新手入门 官方网址:https://whoer.net/zh/ 简介描述:在线查看自己的IP信息工具 「Whoer」是一个专门提供用户在线检测自己IP地址详细信息的网站,…

    2020/03/11
  • javascript中的return语句怎么用?入门攻略_语句指南攻略

    JavaScript return 语句,表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值,由return后面的参数指定。return通常是必要的,因为函数调用的时候计算结果通常是通过返回值带出的。return语句:return语句会终止函数的执行并返回函数的值。语法:return value;参数:value:指定返回的函数值。如果忽略,将返回

    2020/03/22