当前位置: 首页 > news >正文

潍坊网站建设外贸广州市 住房建设局网站首页

潍坊网站建设外贸,广州市 住房建设局网站首页,福州做网站外包,有专门做几口农机的网站简介#xff1a; 若想捉大鱼#xff0c;就得潜入深渊。深渊里的鱼更有力#xff0c;也更纯净。硕大而抽象#xff0c;且非常美丽。 作者#xff1a;张建飞 若想捉大鱼#xff0c;就得潜入深渊。深渊里的鱼更有力#xff0c;也更纯净。硕大而抽象#xff0c;且非常美丽…简介 若想捉大鱼就得潜入深渊。深渊里的鱼更有力也更纯净。硕大而抽象且非常美丽。 作者张建飞 若想捉大鱼就得潜入深渊。深渊里的鱼更有力也更纯净。硕大而抽象且非常美丽。——大卫·林奇 前言 抽象思维是我们工程师最重要的思维能力。因为软件技术 本质上就是一门抽象的艺术。我们的工作是存思维的“游戏”虽然我们在使用键盘、显示器打开电脑可以看到主板、硬盘等硬件。但我们即看不到程序如何被执行也看不到 0101 是如何被 CPU 处理的。 我们工程师每天都要动用抽象思维对问题域进行分析、归纳、综合、判断、推理。从而抽象出各种概念挖掘概念和概念之间的关系对问题域进行建模然后通过编程语言实现业务功能。所以我们大部分的时间并不是在写代码而是在梳理需求理清概念。当然也包括尝试看懂那些“该死的、别人写的”代码。 在我接触的工程师中能深入理解抽象概念的并不多能把抽象和面向对象、架构设计进行有机结合能用抽象思维进行问题分析、化繁为简的同学更是凤毛麟角。 对于我本人而言每当我对抽象有进一步的理解和认知我都能切身感受到它给我在编码和设计上带来的质的变化。同时感慨之前对抽象的理解为什么如此肤浅。如果时间可以倒流的话我希望我在我职业生涯的早期就能充分意识到抽象的重要性能多花时间认真的研究它深刻的理解它这样应该可以少走很多弯路。 什么是抽象 关于抽象的定义百度百科是这样说的 抽象是从众多的事物中抽取出共同的、本质性的特征而舍弃其非本质的特征的过程。具体地说抽象就是人们在实践的基础上对于丰富的感性材料通过去粗取精、去伪存真、由此及彼、由表及里的加工制作形成概念、判断、推理等思维形式以反映事物的本质和规律的方法。实际上抽象是与具体相对应的概念具体是事物的多种属性的总和因而抽象亦可理解为由具体事物的多种属性中舍弃了若干属性而固定了另一些属性的思维活动。[1]Wikipedia 的解释是 抽象是指为了某种目的对一个概念或一种现象包含的信息进行过滤移除不相关的信息只保留与某种最终目的相关的信息。例如一个皮质的足球我们可以过滤它的质料等信息得到更一般性的概念也就是球。从另外一个角度看抽象就是简化事物抓住事物本质的过程。[2]简单而言“抽”就是抽离“象”就是具象字面上理解抽象抽象的过程就是从“具象”事物中归纳出共同特征“抽取”得到一般化Generalization的概念的过程。英文的抽象——abstract 来自拉丁文 abstractio它的原意是排除、抽出。 为了更好的方便你理解抽象让我们先来看一幅毕加索的画如下图所示图的左边是一头水牛是具象的右边是毕加索画是抽象的。怎么样是不是感觉自己一下子理解了抽象画的含义。 可以看到抽象牛只有几根线条不过这几根线条是做了高度抽象之后的线条过滤了水牛的绝大部分细节保留了牛最本质特征比如牛角牛头牛鞭、牛尾巴等等。这种对细节的舍弃使得“抽象牛”具有更好的泛化Generalization能力。 可以说抽象更接近问题的本质也就是说所有的牛都逃不过这几根线条。 抽象和语言是一体的 关于抽象思维我们在百度百科上可以看到如下的定义 抽象思维又称词概念的思维或者逻辑思维是指用词概念进行判断、推理并得出结论的过程。抽象思维以词概念为中介来反映现实。这是思维的最本质特征也是人的思维和动物心理的根本区别。[3]之所以把抽象思维称为词思维或者概念思维是因为语言和抽象是一体的。当我们说“牛”的时候说的就是“牛”的抽象他代表了所有牛共有的特征。同样当你在程序中创建 Cow 这个类的时候道理也是一样。在生活中我们只见过一头一头具象的牛“牛”作为抽象的存在即看不见也摸不着。 这种把抽象概念作为世界本真的看法也是古希腊哲学家柏拉图的最重要哲学思想。柏拉图认为我们所有用感觉感知到的事物都源于相应的理念。他认为具体事物的“名”也就是他说的“理念世界”才是本真的东西具体的一头牛有大有小有公有母颜色、性情、外形各自不同。因此我们不好用个体感觉加以概括但是这些牛既然都被统称为“牛”则说明它们必然都源于同一个“理念”即所谓“牛的理念”或者“理念的牛”所以它们可以用“牛”加以概括。尚且不论“理念世界”是否真的存在这是一个哲学问题但有一点可以确定我们的思考和对概念的表达都离不开语言。[4] 这也是为什么我在做设计和代码审查Code Review的时候会特别关注命名是否合理的原因。因为命名的好坏在很大程度上反映了我们对一个概念的思考是否清晰我们的抽象是否合理反应在代码上就是代码的可读性、可理解性是不是良好以及我们的设计是不是到位。 有人做过一个调查问程序员最头痛的事情是什么通过 Quora 和 Ubuntu Forum 的调查结果显示程序员最头疼的事情是命名。如果你曾经为了一个命名而绞尽脑汁就不会对这个结果感到意外。 就像 Stack Overflow 的创始人 Joel Spolsky 所说的“起一个好名字应该很难因为一个好名字需要把要义浓缩在一到两个词。Creating good names is hard, but it should be hard, because a great name captures essential meaning in just one or two words。” 是的这个浓缩的过程就是抽象的过程。我不止一次的发现当我觉得一个地方的命名有些别扭的时候往往就意味着要么这个地方我没有思考清楚要么是我的抽象弄错了。 关于如何命名我在《代码精进之路》里已经有比较详尽的阐述这里就不赘述了。 我想强调的是语言是明晰概念的基础也是抽象思维的基础在构建一个系统时值得我们花很多时间去斟酌、去推敲语言。在我做过的一个项目中就曾为一个关键实体讨论了两天因为那是一个新概念尝试了很多名字始终感觉到别扭、不好理解。随着我们讨论的深入对问题域理解的深入我们最终找到了一个相对比较合适的名字才肯罢休。 这样的斟酌是有意义的因为明晰关键概念是我们设计中的重要工作。虽然不合理的命名、不合理的抽象也能实现业务功能。但其代价就是维护系统时需要极高的认知负荷。随着时间的推移就没人能搞懂系统的设计了。 抽象的层次性 回到毕加索的抽象画如下图所示如果映射到面向对象编程抽象牛就是抽象类Abstract Class代表了所有牛的抽象。抽象牛可以泛化成更多的牛比如水牛、奶牛、牦牛等。每一种牛都代表了一类Class牛对于每一类牛我们可以通过实例化得到一头具体的牛实例Instance。 从这个简单的案例中我们可以到抽象的三个特点 1. 抽象是忽略细节的。抽象类是最抽象的忽略的细节也最多就像抽象牛只是几根线条而已。在代码中这种抽象可以是 Abstract Class也可以是 Interface。 2. 抽象代表了共同性质。类Class代表了一组实例Instance的共同性质抽象类Abstract Class代表了一组类的共同性质。对于我们上面的案例来说这些共同性质就是抽象牛的那几根线条。 3. 抽象具有层次性。抽象层次越高内涵越小外延越大也就是说它的涵义越小泛化能力越强。比如牛就要比水牛更抽象因为它可以表达所有的牛水牛只是牛的一个种类Class。 抽象的这种层次性是除了抽象概念之外另一个我们必须要深入理解的概念因为小到一个方法要怎么写大到 一个系统要如何架构以及我们后面第三章要介绍的结构化思维都离不开抽象层次的概念。 在进一步介绍抽象层次之前我们先来理解一下外延和内涵的意思 抽象是以概念词语来反映现实的过程每一个概念都有一定的外延和内涵。概念的外延就是适合这个概念的一切对象的范围而概念的内涵就是这个概念所反映的对象的本质属性的总和。例如“平行四边形”这个概念它的外延包含着一切正方形、菱形、矩形以及一般的平行四边形而它的内涵包含着一切平行四边形所共有的“有四条边两组对边互相平行”这两个本质属性。 一个概念的内涵愈广则其外延愈狭反之内涵愈狭则其外延愈广。例如“平行四边形”的内涵是“有四条边两组对边互相平行”而“菱形”的内涵除了这两条本质属性外还包含着“四边相等”这一本质属性。“菱形”的内涵比“平行四边形”的内涵广而“菱形”的外延要比“平行四边形”的外延狭。 所谓的抽象层次就体现在概念的外延和内涵上这种层次性基本可以体现在任何事物上比如一份报纸就存在多个层次上的抽象“出版品”最抽象其内涵最小但外延最大“出版品”可以是报纸也可以是期刊杂志等。 一个出版品一份报纸《旧金山纪事报》5 月 18 日的《旧金山纪事报》当我要统计美国有多少个出版品那么就要用到最上面第一层“出版品”的抽象如果我要查询旧金山 5月18日当天的新闻就要用到最下面第四层的抽象。 每一个抽象层次都有它的用途对于我们工程师来说如何拿捏这个抽象层次是对我们设计能力的考验抽象层次太高和太低都不行。 比如现在要写一个水果程序我们需要对水果进行抽象因为水果里面有红色的苹果我们当然可以建一个 RedApple 的类但是这个抽象层次有点低只能用来表达“红色的苹果”。来一个绿色的苹果你还得新建一个 GreenApple 类。 为了提升抽象层次我们可以把 RedApple 类改成 Apple 类让颜色变成 Apple 的属性这样红色和绿色的苹果就都能表达了。再继续往上抽象我们还可以得到水果类、植物类等。再往上抽象就是生物、物质了。 你可以看到抽象层次越高内涵越小外延越大泛化能力越强。然而其代价就是业务语义表达能力越弱。 具体要抽象到哪个层次要视具体的情况而定了比如这个程序是专门研究苹果的可能到 Apple 就够了如果是卖水果的可能需要到 Fruit如果是植物研究的可能要到 Plant但很少需要到 Object。 我经常开玩笑说你把所有的类都叫 Object把所有的参数都叫 Map 的系统最通用因为 Object 和 Map 的内涵最小其延展性最强可以适配所有的扩展。从原理上来说这种抽象也是对的万物皆对象嘛。但是这种抽象又有什么意义呢它没有表达出任何想表达的东西只是一句正确的废话而已。 越抽象越通用可扩展性越强然而其语义的表达能力越弱。越具体越不好延展然而其语义表达能力很强。所以对于抽象层次的权衡是我们系统设计的关键所在也是区分普通程序员和优秀程序员的关键所在。 软件中的分层抽象无处不在 越是复杂的问题越需要分层抽象分层是分而治之抽象是问题域的合理划分和概念语义的表达。不同层次提供不同的抽象下层对上层隐藏实现细节通过这种层次结构我们才有可能应对像网络通信、云计算等超级复杂的问题。 网络通信是互联网最重要的基础实施但同时它又是一个很复杂的过程你要知道把数据包传给谁——IP协议你要知道在这个不可靠的网络上出现状况要怎么办——TCP 协议。有这么多的事情需要处理我们可不可以在一个层次中都做掉呢当然是可以的但显然不科学。因此ISO制定了网络通信的七层参考模型每一层只处理一件事情低层为上层提供服务直到应用层把HTTP、FTP等方便理解和使用的协议暴露给用户。 编程语言的发展史也是一个典型的分层抽象的演化史。 机器能理解的只有机器语言即各种二进制的 01 指令。如果我们采用 01 的输入方式其编程效率极低学过数字电路的同学体会下用开关实现加减法。所以我们用汇编语言抽象了二进制指令。 然而汇编还是很底层于是我们用 C 语言抽象了汇编语言。而高级语言 Java 是类似于 C 这样低级语言的进一步抽象这种逐层抽象极大的提升了我们的编程效率。 重复代码是抽象的缺失 如果说抽象的本质是共性的话那么我们代码中的重复代码是不是就意味着抽象的缺失呢 //取默认搜索条件 ListString defaultConditions searchConditionCacheTunnel.getJsonQueryByLabelKey(labelKey); for(String jsonQuery : defaultConditions){jsonQuery jsonQuery.replaceAll(SearchConstants.SEARCH_DEFAULT_PUBLICSEA_ENABLE_TIME, String.valueOf(System.currentTimeMillis() / 1000));jsonQueryList.add(jsonQuery); } //取主搜索框的搜索条件 if(StringUtils.isNotEmpty(cmd.getContent())){ListString jsonValues searchConditionCacheTunnel.getJsonQueryByLabelKey(SearchConstants.ICBU_SALES_MAIN_SEARCH);for (String value : jsonValues) {String content StringUtil.transferQuotation(cmd.getContent());value StringUtil.replaceAll(value, SearchConstants.SEARCH_DEFAULT_MAIN, content);jsonQueryList.add(value);} } 是这样的重复代码是典型的代码坏味道其本质问题就是抽象的缺失。因为我们 CtrlC 加 CtrlV 的工作习惯导致没有对共性代码进行抽取或者虽然抽取了只是简单的用了一个 Util 名字没有给到一个合适的名字没有正确的反应这段代码所体现的抽象概念都属于抽象不到位。 有一次我在 Review 团队代码的时候发现有一段组装搜索条件的代码在几十个地方都有重复。这个搜索条件还比较复杂是以元数据的形式存在数据库中因此组装的过程是这样的 首先我们要从缓存中把搜索条件列表取出来然后遍历这些条件将搜索的值填充进去简单的重构无外乎就是把这段代码提取出来放到一个Util类里面给大家复用。然而我认为这样的重构只是完成了工作的一半我们只是做了简单的归类并没有做抽象提炼。 简单分析不难发现此处我们是缺失了两个概念一个是用来表达搜索条件的类——SearchCondition另一个是用来组装搜索条件的类——SearchConditionAssembler。只有配合命名显性化的将这两个概念表达出来才是一个完整的重构。 重构后搜索条件的组装会变成一种非常简洁的形式几十处的复用只需要引用SearchConditionAssembler就好了。 public class SearchConditionAssembler {public static SearchCondition assemble(String labelKey){String jsonSearchCondition getJsonSearchConditionFromCache(labelKey);SearchCondition sc assembleSearchCondition(jsonSearchCondition);return sc;} } 由此可见提取重复代码只是我们重构工作的第一步。对重复代码进行概念抽象寻找有意义的命名才是我们工作的重点。 因此每一次遇到重复代码的时候你都应该感到兴奋想着这是一次锻炼抽象能力的绝佳机会当然测试代码除外。 强制类型转换是抽象层次有问题 面向对象设计里面有一个著名的 SOLID 原则是由 Bob 大叔Robert Martin提出来的其中的 L 代表 LSP就是 Liskov Substitution Principle里氏替换原则。简单来说里氏替换原则就是子类应该可以替换任何父类能够出现的地方并且经过替换以后代码还能正常工作。 思考一下我们在写代码的过程中什么时候会用到强制类型转换呢当然是 LSP 不能被满足的时候也就是说子类的方法超出了父类的类型定义范围为了能使用到子类的方法只能使用类型强制转换将类型转成子类类型。 举个例子在苹果Apple类上有一个 isSweet() 方法是用来判断水果甜不甜的西瓜Watermelon类上有一个 isJuicy() 是来判断水分是否充足的同时它们都共同继承一个水果Fruit类。 此时我们需要挑选出甜的水果和有水分的习惯我们会写一个如下的程序 public class FruitPicker { ​public ListFruit pickGood(ListFruit fruits){return fruits.stream().filter(e - check(e)).collect(Collectors.toList());} ​private boolean check(Fruit e) {if(e instanceof Apple){if(((Apple) e).isSweet()){return true;}}if(e instanceof Watermelon){if(((Watermelon) e).isJuicy()){return true;}}return false;} } 因为pick方法的入参的类型是 Fruit所以为了获得 Apple 和 Watermelon 上的特有方法我们不得不使用 instanceof 做一个类型判断然后使用强制类型转换转成子类类型以便获得他们的专有方法很显然这是违背了里式替换原则的。 这里问题出在哪里对于这样的代码我们要如何去优化呢仔细分析一下我们可以发现根本原因是因为 isSweet 和 isJuicy 的抽象层次不够站在更高抽象层次也就是 Fruit 的视角看我们挑选的就是可口的水果只是具体到苹果我们看甜度具体到西瓜我们看水分而已。 因此解决方法就是对 isSweet 和 isJuicy 进行抽象并提升一个层次在 Fruit 上创建一个 isTasty() 的抽象方法然后让苹果和西瓜类分别去实现这个抽象方法就好了。 下面是重构后的代码通过抽象层次的提升我们消除了 instanceof 判断和强制类型转换让代码重新满足了里式替换原则。抽象层次的提升使得代码重新变得优雅了。 public class FruitPicker { public ListFruit pickGood(ListFruit fruits){ return fruits.stream().filter(e - check(e)). collect(Collectors.toList()); } //不再需要instanceof和强制类型转换 p rivate boolean check(Fruit e) { return e.isTasty(); }} 所以每当我们在程序中准备使用 instanceof 做类型判断或者用 cast 做强制类型转换的时候。每当我们的程序不满足 LSP 的时候。你都应该警醒一下好家伙这又是一次锻炼抽象能力的绝佳机会。 如何提升抽象思维能力 抽象思维能力是我们人类特有的、与生俱来的能力除了上面说的在编码过程中可以锻炼抽象能力之外我们还可以通过一些其他的练习不断的提升我们的抽象能力。 多阅读 为什么阅读书籍比看电视更好呢因为图像比文字更加具象阅读的过程可以锻炼我们的抽象能力、想象能力而看画面的时候会将你的大脑铺满较少需要抽象和想象。 这也是为什么我们不提倡让小孩子过多的暴露在电视或手机屏幕前的原因因为这样不利于他抽象思维的锻炼。 抽象思维的差别让孩子们的学习成绩从初中开始分化许多不能适应这种抽象层面训练的就去读技校了因为技校比大学会更加具象车铣刨磨、零部件都能看得见摸得着。体力劳动要比脑力劳动来的简单。 多总结沉淀 小时候不理解语文老师为什么总是要求我们总结段落大意、中心思想什么的。现在回想起来这种思维训练在基础教育中是非常必要的其实质就是帮助学生提升抽象思维能力。 记录也是很好的总结习惯。就拿读书笔记来说最好不要原文摘录书中的内容而是要用自己的话总结归纳书中的内容这样不仅可以加深理解而且还可以提升自己的抽象思维能力。 我从四年前开始系统的记录笔记做总结沉淀构建自己的知识体系。这种思维训练的好处显而易见可以说我之前写的《从码农到工匠》和现在正在写的《程序员必备的思维能力》都离不开我总结沉淀的习惯。 命名训练 每一次的变量命名、方法命名、类命名都是一次难得的抽象思维训练机会前面已经说过了语言和抽象是一体的命名的好坏直接反应了我们的问题域思考的是否清晰反映了我们抽象的是否合理。 现实情况是我们很多的工程师常常忽略了命名的重要性只要能实现业务功能名字从来就不是重点。 实际上这是对系统的不负责任也是对自己的不负责任更是对后期维护系统的人不负责任。写程序和写文章有很大的相似性本质上都是在用语言阐述一件事情。试想下如果文章中用的都是些词不达意的句子这样的文章谁能看得懂谁又愿意去看呢。 同样我一直强调代码要显性化的表达业务语义其中命名在这个过程中扮演了极其重要的角色。为了代码的可读性为了系统的长期可维护性为了我们自身抽象思维的训练我们都不应该放过任何一个带有歧义、表达模糊、意不清的命名。 领域建模训练 对于技术同学我们还有一个非常好的提升抽象能力的手段——领域建模。当我们对问题域进行分析、整理和抽象的时候当我们对领域进行划分和建模的时候实际上也是在锻炼我们的抽象能力。 我们可以对自己工作中的问题域进行建模当然也可以通过阅读一些优秀源码背后的模型设计来学习如何抽象、如何建模。比如我们知道 Spring 的核心功能是 Bean 容器那么在看Spring源码的时候我们可以着重去看它是如何进行Bean管理的它使用的核心抽象是什么不难发现Spring 是使用了 BeanDefinition、BeanFactory、BeanDefinitionRegistry、BeanDefinitionReader 等核心抽象实现了 Bean 的定义、获取和创建。抓住了这些核心抽象我们就抓住了 Spring 设计主脉。 除此之外我们还可以进一步深入思考它为什么要这么抽象这样抽象的好处是什么以及它是如何支持 XML 和 Annotation注解这两种关于 Bean 的定义的。 这样的抽象思维锻炼和思考对提升我们的抽象能力和建模能力非常重要。关于这一点我深有感触初入职场的时候当我尝试对问题域进行抽象和建模的时候会觉得无从下手建出来的模型也感觉很别扭。 然而经过长期的、刻意的学习和锻炼之后很明显可以感觉到我的建模能力和抽象能力都有很大的提升。不但分析问题的速度更快了而且建出来的模型也更加优雅了。 小结 抽象思维是程序员最重要的思维能力抽象的过程就是寻找共性、归纳总结、综合分析提炼出相关概念的过程。语言和抽象是一体的抽象思维也叫词思维因为抽象的概念只能通过语言才能表达出来。抽象是有层次性的抽象层次越高内涵越小外延越大扩展性越好反之抽象层次越低内涵越大外延越小扩展性越差但语义表达能力越强。对抽象层次的拿捏体现了我们的设计功力视具体情况而定抽象层次既不能太高也不能太低。重复代码意味着抽象缺失强制类型转换意味着抽象层次有问题我们可以利用这些信号来重构代码让代码重新变的优雅。我们可以通过刻意练习来提升抽象能力这些练习包括阅读、总结、命名训练、建模训练等。 原文链接 本文为阿里云原创内容未经允许不得转载。
http://www.huolong8.cn/news/49693/

相关文章:

  • 企业彩铃制作网站环境设计专业就业方向
  • 建设网站用动态ip还是静态ip网站导航图怎么做的详细步骤
  • 网站别人备案怎么办网站建设的主要客户群体
  • 用手机怎么看自己做的网站网页设计网站规划报告
  • 学校门户网站建设方案织梦做的网站被黑了
  • 网站的主流趋势图片压缩wordpress
  • 淮安做网站卓越凯欣wordpress 物流主题
  • 漳州微网站建设价格我要做个网站该怎么做
  • 网站建设的几个要素企业标准官网入口
  • 网站搭建徐州百度网络数据采集发布 wordpress
  • 太原网站运营优化wordpress 响应分页
  • 万户网站天下win7和wordpress
  • 福建省建设系统网站贵州省领导班子名单一览表
  • 住房和城乡建设厅门户网站西安做网站哪家比较好
  • 怎么写简历 网站开发WordPress怎么封装APP
  • 报告网站开发环境建设部网站投诉核查
  • 烟台网站制作套餐服装网页设计网站
  • 中盛腾龙建设工程有限公司网站为什么语音转文字里面没有海南的
  • 四川做网站个人名片模板
  • 郑州网站推广公司上海专业高端网站建设
  • 网站中英文切换代码做网站配置服务器
  • 公司网站备案网址建网站 主流软件
  • 建设网站需要什么条件建筑公司招聘信息
  • 常用企业网站模板对比开发新软件需要多少钱
  • 做网站通过什么挣钱青岛新闻最新消息
  • 网站策划书撰写流程制作一个介绍洛阳网站
  • 山东网站建设负面消息处理怎样做士产品销售网站
  • 阿坝住房和城乡建设厅网站网站域名怎么设置
  • 旅行网站定制公司网站开发应该学哪门语言
  • 阿里云 oss做网站线上平台名称大全