2 lines
8.0 KiB
JavaScript
2 lines
8.0 KiB
JavaScript
import{_ as a,c as e,o as l,a4 as i}from"./chunks/framework.DtvhUNIn.js";const u=JSON.parse('{"title":"3.X 聊聊设计模式和程序设计","description":"","frontmatter":{},"headers":[],"relativePath":"技术资源汇总(杭电支持版)/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md","filePath":"技术资源汇总(杭电支持版)/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md"}'),p={name:"技术资源汇总(杭电支持版)/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md"},t=i('<h1 id="_3-x-聊聊设计模式和程序设计" tabindex="-1">3.X 聊聊设计模式和程序设计 <a class="header-anchor" href="#_3-x-聊聊设计模式和程序设计" aria-label="Permalink to "3.X 聊聊设计模式和程序设计""></a></h1><p><em>Author: yyl Last revised 2022/08/07</em></p><h2 id="前言" tabindex="-1">前言 <a class="header-anchor" href="#前言" aria-label="Permalink to "前言""></a></h2><p>在开始讲内容之前,我觉得我得首先聊一聊到底为什么我们需要这些东西。为什么我们会需要设计模式呢?</p><p>这个问题并不可笑,也不幼稚,事实上,很多东西红极一时,最终却被历史证明是不被需要的。类似的事情太多了,可以是一种理念,比如日心说,可以是一种产品,比如软驱、RAMBUS 内存,等等。历史已经丢弃了太多不被需要的东西了。</p><p>学习本身是有成本的事情,如果在开始之前能够理解为什么要开始就更好,尽管很多时候我们做不到这件事,但也不能忘了这件事。</p><p>上个世纪 80~90 年代的时候,人们试图通过“设计模式”这一工具,抽象总结所有的软件设计方法,构建一个无敌的知识库。最终使得软件工程就像堆积木一样简单,避免软件随时间变得杂乱的熵增问题,但毫无疑问这是失败的,你永远无法抽象总结所有东西,设计模式的巅峰,可能是在 JDK 之中。在阅读 Java 自身提供的诸多 API 时,你会发现其中蕴藏了大量的设计模式,而且是赤裸裸地把使用了的设计模式写在了类名中,如“XXXListener”,很少有另一个语言也是这样的。</p><p>设计模式并没有完全成功,但也没有完全失败。他现在以一种“术语”的形式存在,帮助人们理解常见的编程范式。——这是什么意思呢?举个例子,如果你尝试和同事说明你的一个设计时,你说,它首先有两个类,一个类提供了一个通用的接口,可以被另一个类注册,另一个类则负责把所有的动作通知给已经注册的类。这种说法显然非常繁琐,对方也未必能理解你的意思。但如果你说,这里使用了监听者模式,如果你的同事碰巧学习过一些设计模式,他就能立即理解你的意思。即使他没有学习过相关知识,只要简单百度一下也能理解个大概。这是当今设计模式的一个重要作用。</p><p>另一个重要作用则是它的本源了,用于总结抽象程序设计的范式。但并不是说要你写的所有代码能用设计模式的就都用设计模式,这更多是提供给你一种选项,让你能够充分权衡。关于这部分,下文还会有说明。</p><p>目前的设计模式,主要集中在如何避免程序复杂度上。</p><p>什么是程序复杂度呢?就是说你今天写了个软件,明天给他加功能的时候发现这个程序不怎么可维护,于是直接在之前的逻辑上加了个 if,你的一个 if 通常不会有什么大问题,程序复杂性问题是日积月累的。随着大家都在不同的地方写自己的 if,整个程序最终会变得不可维护。可能一个微小的改动会导致很多地方的 if 出现不符合预期的判断,可能终有一天有一个需求无法再用 if 来实现,等等。</p><p>为了解决这个问题,设计模式使用的方法是原则,通过制定一系列的原则,并确保大家都遵守,来避免代码腐烂。</p><h2 id="拿个锤子-见什么都是钉子" tabindex="-1">拿个锤子,见什么都是钉子 <a class="header-anchor" href="#拿个锤子-见什么都是钉子" aria-label="Permalink to "拿个锤子,见什么都是钉子""></a></h2><p>设计模式,或者说广义的程序设计架构的初学者,很多都会想去设计一个“完美的架构”。</p><p>当就像计算机程序设计本身是关于权衡的艺术一样,学习程序架构也不能看见什么都上架构。下面举例子具体说明。</p><p>你要设计一个小程序给自己用,这个程序的作用是定时读取一边本地硬盘上的全部文件,通过 sha256 算法生成每个文件的文件摘要,比对文件是否遭到篡改,如果遭到了篡改就报个警。</p><p>如果你没有学习过这些乱七八糟的设计模式,我想你大概会这么做:</p><p>main():</p><p>walk("/");</p><p>walk(String path):</p><p>For file : os.listfile(path):</p><p>// 检查文件摘要</p><p>For dir : os.listdir(path):</p><p>walk(dir);</p><p>但如果你很不幸,学习过一些设计模式,或者说有一些程序设计经验,你会开始考虑一下问题:</p><ol><li>我用什么语言实现?这个语言的代码文件组织有没有推荐的架构?(比如,第三方包引用了放在哪里?文件加密的 util 是放在内部还是封装成可供其他人引用的三方包?)</li><li>选用什么样的依赖管理机制?</li><li>编译最终产物的时候用什么工具,make 还是 maven 还是 gradle 还是 shell 还是 python?...</li><li>walk 能不能兼容不同平台的系统?在 win 下面能不能用?</li><li>有没有什么设计模式可以用?(开始翻书)</li><li>卧槽,用官方推荐的组织架构的话这个程序有点单薄啊,要不要加点功能上去</li><li>...</li></ol><p>要明白,拿着个锤子绝不能看什么都是钉子。</p><p>设计模式本身也是权衡的艺术,我们今天经常说的东西,比如 DDD,SOA,微服务,monorepo,也都是一种广义的设计模式。权衡什么呢?权衡的是:是要维持程序在发生功能变动时的可拓展性、降低程序维护复杂度,还是追求程序的快速实现。</p><p>拿上文的例子来说,如果你的所有程序都是在运行 Linux 上的,这个也只是给你自己快速检查文件完整性,之后也几乎不存在增加新的功能的可能,为什么不随便找个脚本语言快速十几行写完呢?</p><h2 id="如何学习" tabindex="-1">如何学习 <a class="header-anchor" href="#如何学习" aria-label="Permalink to "如何学习""></a></h2><p>个人认为,现在所谓的设计模式分两种,第一种是狭义的设计模式,就是各种设计模式的堆积。</p><p>此外,还有广义的设计模式,这块内容就很多了,但也是讨论如何降低代码复杂度的,包括:</p><ol><li>程序代码怎么组织(在开发 web 应用时这块经常有争议,可以参考 <a href="https://cloud.tencent.com/developer/article/1837487" target="_blank" rel="noreferrer">浅析整洁架构之道 (二) 初步了解 The Clean Architecture</a>)</li><li>程序之间怎么组织(是放在一个编成个大的,还是微服务,还是用 FaaS 之类的变体)</li><li>一些帮助减少程序复杂度的代码原则:<a href="https://zhuanlan.zhihu.com/p/82324809" target="_blank" rel="noreferrer">设计模式之 SOLID 原则</a></li></ol><p>这部分的学习不能操之过急。个人的建议是:</p><ol><li>学习一些设计模式,看完两次肯定没什么感觉,甚至会觉得看了个寂寞(可以先看看 Head first 设计模式)</li><li>忘了他,去写你自己的代码,遇到复杂度诅咒了再考虑如何解决</li><li>读他人的优秀代码,想一想这里他为什么要这么写,换成是你的话会怎么写,各自有什么利弊</li><li>重复 1</li></ol>',35),r=[t];function o(n,_,h,s,c,d){return l(),e("div",null,r)}const m=a(p,[["render",o]]);export{u as __pageData,m as default};
|