一.写这篇文章的原因
1.C语言能够使用设计模式吗??
2.为什么要有软件设计模式?不学行不行?
3.怎么能够成为一个好的开发者,为什么有经验的人比你开发快,代码架构还好?
4.C++作为C的扩展,为什么开始使用面向对象?为什么都说C++难学?
5.JAVA,C++中都有设计模式,到底和我们的项目开发有什么联系?
在不断的学习提升中,这些问题一直困扰着我,但是一直得不到一个很好的答案,不经意的看到一篇文章后,恍然大悟,决定写这篇文章提炼一下自己理解的重点
希望更多感同身受的人从这个文章中收益。
原文章地址如下,可详细阅读:
https://www.jianshu.com/p/18d1d582f5c2
二. 软件设计的演变过程
看到了这个软件设计的过程,感觉就像是自己在学习路上的不断演化,其实我们一直都只是个使用者,以前困惑的一些东西其实早有答案。
只是有时候我们只知道某个知识点要学,但是为什么要学,并不清楚。
发展的过程(本人很喜欢看发展史,可以让我们以上帝视角看待问题,更像是一个树根,知其因果,就不会被各种观点所动摇)
1.软件设计初始阶段
0世纪60年代以前,计算机刚刚投入实际使用,软件设计往往只是为了一个特定的应用而在指定的计算机上设计和编制,采用密切依赖于计算机的机器代码或汇编语言,软件的规模比较小,文档资料通常也没有,很少使用系统化的开发方法,设计软件往往等同于编制程序,基本上是自给自足的私人化的软件生产方式。
20世纪60年代中期,大容量、高速度计算机的出现,使得计算机的应用范围迅速扩大,软件开发急剧增长。高级语言逐渐流行(FORTRAN 66),操作系统开始发展(IBMSYS),第一代数据库管理系统慢慢诞生(IMS),软件系统的规模越来越大,复杂程度越来越高,软件可靠性问题也越来越突出。既有自给自足的私人化的软件生产方式不能再满足要求,迫切需要改变,于是软件危机开始爆发,即落后的软件生产方式无法满足迅速增长的计算机软件需求,导致软件的开发与维护出现一系列严重的问题:
- 软件开发费用和进度失控
- 软件的可靠性差
- 生产出来的软件难以维护
1968年北大西洋公约组织的计算机科学家在联邦德国召开国际会议,第一次讨论软件危机问题,并正式提出“软件工程”一词,从此一门新兴的工程学科应运而生。
总结:随着发展,需求越来越多,机器代码汇编语言已经跟不上节奏了,急啊,咋办啊,先开个会吧!!
2.结构化程序设计
结构化程序设计由迪克斯特拉(E.W.dijkstra)在1969年提出,是以模块化设计为中心,将待开发的软件系统划分为若干个相互独立的模块,这样使完成每一个模块的工作变单纯而明确,为设计一些较大的软件打下了良好的基础。
由于模块相互独立,因此在设计其中一个模块时,不会受到其它模块的牵连,因而可将原来较为复杂的问题化简为一系列简单模块的设计。模块的独立性还为扩充已有的系统和建立新系统带来了不少的方便,因为我们可以充分利用现有的模块作积木式的扩展。
按照结构化程序设计的观点,任何算法功能都可以通过由程序模块组成的三种基本程序结构的组合: 顺序结构、选择结构和循环结构来实现。
结构化程序设计主要表现在一下三个方面:
- 自顶向下,逐步求精。将编写程序看成是一个逐步演化的过程,将分析问题的过程划分成若干个层次,每一个新的层次都是上一个层次的细化。
- 模块化。将系统分解成若干个模块,每个模块实现特定的功能,最终的系统由这些模块组装而成,模块之间通过接口传递信息。
- 语句结构化。在每个模块中只允许出现顺序、分支和循环三种流程结构的语句。
结构化程序设计的概念、方法和支持这些方法的一整套软件工具,构成了结构化革命。这是计算机问世以来对计算机界影响最大的一个软件概念,被称为软件发展中的第三个里程碑,其影响比前两个里程碑(子程序、高级语言)更为深远。
1972年,美国贝尔实验室的D.M.Ritchie在B语言的基础上最终设计出了一种新的语言,他取了BCPL的第二个字母作为这种语言的名字,这就是C语言。1973年初,C语言的主体开发完成,并逐步成为结构化编程语言中最流行的语言。
尼古拉斯沃思(Nicklaus Wirth)教授在编程界提出了一个著名的公式:程序 = 数据结构 + 算法
结构化程序设计是用计算机的思维方式去处理问题,将数据结构和算法分离。数据结构描述待处理数据的组织形式,而算法描述具体的操作过程。我们用函数把这些算法一步一步的实现,使用的时候一个一个的依次调用就可以了。
说明:“面向过程”这个词是在“面向对象”出现之后为与之相对而提出的,它可以看作是“结构化”的别名。
总结:这个阶段,大神们各显神通,很是给力,结构化设计,c语言,等一些延用至今的语言和思想出现。为现在的计算机发展奠定了基础。
3. 面向对象程序设计
结构化编程的风靡在一定程度上缓解了软件危机,然而好景不长,随着硬件的快速发展,业务需求越来越复杂,以及编程应用领域越来越广泛,第二次软件危机很快就到来了。
第二次软件危机的根本原因还是在于软件生产力远远跟不上硬件和业务的发展,相比 第一次软件危机主要 体现在“复杂性”,第二次软件危机主要体现在“可扩展性”、“可维护性”上面。传统的面向过程(包括 结构化程序设计)方法已经越来越不能适应快速多变的业务需求了,软件领域迫切希望找到新的银弹来解 决软件危机,在这种背景下,面向对象的思想开始流行起来。
面向对象的思想并不是在第二次软件危机后才出现的,早在 1967 年的 Simula 语言中就开始提出来了,但 第二次软件危机促进了面向对象的发展。
而C++(1983)恰好在这个时期诞生,自然而然地,C++就选择了支持面向对象程序设计的思想。同样也促进了面向对象思想的发展。
之前我们也提到面向过程的结构化设计好比是一份蛋炒饭,面向对象的设计好比是一份盖饭。盖浇饭的好处就是”菜”“饭”分离,从而提高了制作盖浇饭的灵活性。
当我们习惯了面向过程(结构化)编程时,发现在程序过程中到处找不到需要面向对象的地方,最主要的原因,是思维没有转变。程序员通常在拿到一个需求的时候,第一个反应就是如何实现这个需求,这是典型的面向过程的思维方式,而且可能很快就实现了它。而面向对象,面对的却是客体,第一步不是考虑如何实现需求,而是进行需求分析,就是根据需求找到其中的客体,再找到这些客体之间的联系。因此面向过程和面向对象的思维转变的关键点,就是在第一步设计,拿到需求后,一定先不要考虑如何实现它,而是通过UML建模,然后按照UML模型去实现它。这种思路的转变,可能需要个过程。(这也是一个新手和老手开发项目的区别)
4.设计模式
设计面向对象的软件比较困难,而设计可复用的面向对象的软件就更加困难。必须找到相关的对象,以适当的粒度将它们归类,再定义类的接口和继承层次,建立对象之间的基本关系。有经验的面向对象设计者的确能做出良好的设计,而新手则面对众多选择无从下手,总是求助于以前使用过的非面向对象技术。新手需要花费较长时间领会良好的面向对象设计是怎么回事,而有经验的设计者显然知道一些新手不知道的东西,这又是什么呢?
内行的设计者知道,不是解决任何问题都要从头做起,他们更愿意复用以前使用过的解决方案。当找到一个好的解决方案,他们会一遍又一遍地使用。这些经验是他们成为内行的部分原因。
GoF将模式的概念引入软件工程领域,这标志着软件模式的诞生。软件模式并非仅限于设计模式,还包括架构模式、分析模式和过程模式等。实际上,在软件开发生命周期的每一个阶段都存在着一些被认同的模式。软件模式与具体的应用领域无关,也就是说无论从事的是移动开发、桌面开发、Web开发还是嵌入式软件的开发,都可以使用软件模式。
在软件模式中,设计模式是研究最为深入的分支,它融合了众多专家的设计经验,已经在成千上万的软件中得以应用。1995年,GoF将收集和整理好的23种设计模式汇编成了一本名叫《设计模式》的书,该书的出版也标志着设计模式时代的到来。这些模式解决特定的设计问题,使面向对象设计更灵活和优雅,最终复用性更好。他们帮助设计者将新的设计建立在以往工作的基础上,复用以往成功的设计方案。一个熟悉这些模式的设计者不需要再去发现它们,而能够立即将它们应用于设计问题中。
设计模式使人们可以更加简单方便地复用成功的设计和体系结构,将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。设计模式帮助你做出有利于系统复用的选择,避免设计损害了系统的复用性。简而言之,设计模式可以帮助设计者更快更好地完成系统设计。
守破离是武术中一种渐进的学习方法:
- 第一步——守,遵守规则直到充分理解规则并将其视为习惯性的事。
- 第二步——破,对规则进行反思,寻找规则的例外并“打破”规则。
- 第三步——离,在精通规则之后就会基本脱离规则,抓住其精髓和深层能量。
设计模式的学习也是一个守破离的过程:
- 第一步——守,在设计和应用中模仿既有设计模式,在模仿中要学会思考。
- 第二步——破,熟练使用基本设计模式后,创造新的设计模式。
- 第三步——离,忘记所有设计模式,在设计和应用中潜移默化的使用。
当然,如果你不学设计模式,你可能也在无意识的使用一些设计模式,但是这个在跟学过以后再无意识的使用设计模式,应该隔着两重境界吧,有点理解张无忌在学太极时说的话了。
总结:设计面向对象的软件比较困难,而设计可复用的面向对象的软件就更加困难。而大神们已经为我们设计了成熟的设计方法供我们复用,你还不学?
5.设计原则
我们生活在一个充满规则的世界里,在复杂多变的外表下,万事万物都被永恒的真理支配并有规律的运行着。
面向对象设计原则是我们用于评价一个设计模式的使用效果的重要指标之一,比如“XXX模式符合YYY原则”、“XXX模式违反了ZZZ原则”。
其实就好比说我们有了各式各样的模板(每个人的思路和方式不同),想要共用,我们要提出一个规范,大家都按这个规则办事。所以设计原则的出现是必然的。
如果不规定电压标准220v,电器咋供电,岂不是乱套了
6.领域驱动设计(DDD)
一直以来,我们按照传统的方式开发软件,如下图所示:
有些时候,分析师站在分析模型的角度认为某个需求较容易实现,而设计师站在设计模型的角度认为该需求较难实现,那么双方都很难理解对方的模型。(有点像项目经理和程序员关系)
抛弃将分析模型与设计模型分离的做法,寻找单个模型来满足两方面的要求,这就是领域模型。
许多系统的真正复杂之处不在于技术,而在于领域本身,在于业务用户及其执行的业务活动。如果在设计时没有获得对领域的深刻理解,没有通过模型将复杂的领域逻辑以模型概念和模型元素的形式清晰地表达出来,那么无论我们使用多么先进、多么流行的平台和设施,都难以保证项目的真正成功。
- 以一种领域专家、设计人员和开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型;
- 由领域模型驱动软件设计,用代码来表达该领域模型。
由此可见,领域驱动设计的核心是建立正确的领域模型。
一个通用领域驱动设计的架构性解决方案包含四个概念层,就是经典的四层模型,如下图所示:
- User Interface为用户界面/展现层:负责向用户展现信息以及解释用户命令。
- Application为应用层:定义软件要完成的所有任务。对外为展现层提供各种应用功能(包括查询或命令),对内调用领域层(领域对象或领域服务)完成各种业务逻辑,应用层不包含业务逻辑。
- Domain为领域层:负责表达业务概念,业务状态信息以及业务规则,领域模型处于这一层,是业务软件的核心。
- Infrastructure层为基础实施层:向其他层提供通用的技术能力;提供了层间的通信;为领域层实现持久化机制;总之,基础设施层可以通过架构和框架来支持其他层的技术需求。
总结:设计模式很好,但是要根据不同领域进行选择和变化,从概括到细分的过程。
7.DCI
DCI目前广泛被作为对DDD的一种发展和补充,用于基于面向对象的领域建模。DCI通过显示的用role对行为进行建模,同时让role在context中可以和对应的领域对象进行绑定(cast),从而既解决了数据边界和行为边界不一致的问题,也解决了领域对象中数据和行为高内聚低耦合的问题。
单纯使用ddd可能无法很好的维护软件的复杂度(例如下面这种)
人有多重角色,不同的角色履行的职责不同:
- 作为父母:我们要给孩子讲故事,陪他们玩游戏,哄它们睡觉;
- 作为子女:我们则要孝敬父母,听取他们的人生建议;
- 作为下属:在老板面前,我们需要听从其工作安排;
- 作为上司:需要安排下属工作,并进行培养和激励;
这里人(大对象)聚合了多个角色(小类),在某种场景下,只能扮演特定的角色:
- 在孩子面前,我们是父母;
- 在父母面前,我们是子女;
- 职场上,在上司面前,我们是下属;
- 在下属面前,你是上司
8.领域专用语言(DSL)
像我们平时接触到的C、C++和Java等都属于通用语言,可以为各个领域编程,虽然通用性有余,但针对性不强,所以DSL是为了弥补通用语言的这个劣势而出现的。
常见的 DSL
- 软件构建领域 Ant
- UI 设计师 HTML
- 硬件设计师 VHDL
DSL 的特点
- 用于专门领域,不能用于其他领域
- 表现力有限
- 不描述解答域,仅描述问题域
DSL 与通用编程语言的区别
- DSL 供非程序员使用,供领域专家使用
- DSL 有更高级的抽象,不涉及类似数据结构的细节
- DSL 表现力有限,其只能描述该领域的模型,而通用编程语言能够描述任意的模型
9.微服务架构
软件“教父”Martin Fowler在2012年提出微服务这一概念,于是出现了两种服务架构模式,即单体架构模式和微服务架构模式
微服务(micro services)这个概念不是新概念,很多公司已经在实践了,例如亚马逊、Google、FaceBook、Alibaba。
微服务架构模式(Microservices Architecture Pattern)的目的是将大型的、复杂的、长期运行的应用程序构建为一组相互配合的服务,每个服务都可以很容易得局部改良。