软件开发总结

已剪辑自: https://zhuanlan.zhihu.com/p/50382755

软件开发方法是一种使用早已定义好的技术集及符号表示习惯,来组织软件生产的过程。

软件开发需要严谨工作方法。软件开发的方法有很多,不同的开发方法适用于不同的软件项目,具体使用哪种方法,还需要根据软件情况来确定。

结构化方法

结构化方法由结构化分析、结构化设计、结构化程序设计构成,它是一种面向数据流的开发方法。

结构化分析

是根据分解与抽象的原则,按照系统中数据处理的流程,用数据流图来建立系统的功能模型,从而完成需求分析工作。

结构化设计

根据模块独立性准则、软件结构优化准则将数据流图转换为软件的体系结构,用软件结构图来建立系统的物理模型,实现系统的概要设计。

结构化程序设计

使用3种基本控制结构构造程序,任何程序都可以由顺序、选择和重复3种基本控制结构构造。

结构化方法总的指导思想是自顶向下、逐层分解,它的基本原则是功能的分解与抽象。适合于数据处理领域的问题,不适合解决大规模的、特别复杂的项目,且难以适应需求的变化。

Jackson方法

Jackson方法是一种面向数据结构的开发方法。

JSP(JacksonStructure Programming)方法是以数据结构为驱动的,适合于小规模的项目。JSP方法首先描述问题的输入/输出数据结构,分析其对应性,然后推出相应的程序结构,从而给问题的软件过程描述。

JSD方法是JSP方法的扩展,是一个完整的系统开发方法。首先建立现实世界的模型,再确定系统的功能需求,对需求的描述特别强调操作之间的时序性。它是以事件作为驱动的,是一种基于进程的开发方法,所以适用于时序特别较强的系统,包括数据处理系统和一些实时控制系统。

原型方法

原型方法比较适合于用户需求不清、需求经常变化的情况。当系统规模不是很大也不太复杂时,采用该方法比较好。

面向对象方法

面向对象方法正是以对象作为最基本的元素,它也是分析问题、解决问题的核心。面向对象方法包括面向对象分析、面向对象设计和面向对象实现。

UML是面向对象的标准建模语言,通过统一的语义和符号表示,使各种方法的建模过程和表示统一起来,现已成为面向对象建模的工业标准。

敏捷方法

极限编程(XP):XP是一种轻量级(敏捷)、高效、低风险、柔性、可预测的、科学的软件开发方式。它由价值观、原则、实践和行为4个部分组成,彼此相互依赖、关联,并通过行为贯穿于整个生存周期。

4大价值观:沟通、简单性、反馈、勇气

5个原则:快速反馈、简单性假设、逐步修改、提倡更改、优质工作

12个最佳实践:计划游戏(快速制定计划、随着细节的不断变化而完善)、小型发布(系统的设计要能够尽可能早地交付)、隐喻(找到合适的比喻传达信息)、简单设计(只处理当前的需求,使设计保持简单)、测试先行(先写测试代码,然后再编写程序) 、重构(重新审视需求和设计,重新明确地描述他们以符合新的和现有的需求)、结对编程、集体代码所有制、继续集成(可以按日甚至按小时为客户提供可运行的版本)、每周工作40小时、现场客户和编码标准。

水晶法

水晶法认为每一个不同的项目都需要一套不同的策略、约定和方法论。

并列争求法

并列争求法使用迭代的方法,其中,把每30天一次的迭代称为一个“冲刺”,并按需求的优先级别来实现产品。

自适应软件开发(ASD)

ASD有6个基本的原则

  • 有一个使命作为指导;
  • 特征被视为客户价值的关键点;
  • 过程中的等待是很重要的,因此“重做”与“做”同样关键
  • 变化不被视为改正,而是被视为对软件开发实际情况的调查。
  • 确定的交付时间迫使开发人员认真考虑每一个生产的版本的关键需求。
  • 风险也包含其中。

软件设计的演变过程

已剪辑自: https://www.jianshu.com/p/18d1d582f5c2

“Design is there to enable you to keep changing the software easily in the long term” —— Kent Beck

img

software-design-evolution.png

序言

20世纪60年代以前,计算机刚刚投入实际使用,软件设计往往只是为了一个特定的应用而在指定的计算机上设计和编制,采用密切依赖于计算机的机器代码或汇编语言,软件的规模比较小,文档资料通常也没有,很少使用系统化的开发方法,设计软件往往等同于编制程序,基本上是自给自足的私人化的软件生产方式。

20世纪60年代中期,大容量、高速度计算机的出现,使得计算机的应用范围迅速扩大,软件开发急剧增长。高级语言逐渐流行(FORTRAN 66),操作系统开始发展(IBMSYS),第一代数据库管理系统慢慢诞生(IMS),软件系统的规模越来越大,复杂程度越来越高,软件可靠性问题也越来越突出。既有自给自足的私人化的软件生产方式不能再满足要求,迫切需要改变,于是软件危机开始爆发,即落后的软件生产方式无法满足迅速增长的计算机软件需求,导致软件的开发与维护出现一系列严重的问题:

  1. 软件开发费用和进度失控
  2. 软件的可靠性差
  3. 生产出来的软件难以维护

1968年北大西洋公约组织的计算机科学家在联邦德国召开国际会议,第一次讨论软件危机问题,并正式提出“软件工程”一词,从此一门新兴的工程学科应运而生。

结构化程序设计

结构化程序设计由迪克斯特拉(E.W.dijkstra)在1969年提出,是以模块化设计为中心,将待开发的软件系统划分为若干个相互独立的模块,这样使完成每一个模块的工作变单纯而明确,为设计一些较大的软件打下了良好的基础。
由于模块相互独立,因此在设计其中一个模块时,不会受到其它模块的牵连,因而可将原来较为复杂的问题化简为一系列简单模块的设计。模块的独立性还为扩充已有的系统和建立新系统带来了不少的方便,因为我们可以充分利用现有的模块作积木式的扩展。
按照结构化程序设计的观点,任何算法功能都可以通过由程序模块组成的三种基本程序结构的组合: 顺序结构、选择结构和循环结构来实现。

结构化程序设计主要表现在一下三个方面:

  1. 自顶向下,逐步求精。将编写程序看成是一个逐步演化的过程,将分析问题的过程划分成若干个层次,每一个新的层次都是上一个层次的细化。
  2. 模块化。将系统分解成若干个模块,每个模块实现特定的功能,最终的系统由这些模块组装而成,模块之间通过接口传递信息。
  3. 语句结构化。在每个模块中只允许出现顺序、分支和循环三种流程结构的语句。

结构化程序设计的概念、方法和支持这些方法的一整套软件工具,构成了结构化革命。这是计算机问世以来对计算机界影响最大的一个软件概念,被称为软件发展中的第三个里程碑,其影响比前两个里程碑(子程序、高级语言)更为深远。

1972年,美国贝尔实验室的D.M.Ritchie在B语言的基础上最终设计出了一种新的语言,他取了BCPL的第二个字母作为这种语言的名字,这就是C语言。1973年初,C语言的主体开发完成,并逐步成为结构化编程语言中最流行的语言。

尼古拉斯沃思(Nicklaus Wirth)教授在编程界提出了一个著名的公式:程序 = 数据结构 + 算法
结构化程序设计是用计算机的思维方式去处理问题,将数据结构和算法分离。数据结构描述待处理数据的组织形式,而算法描述具体的操作过程。我们用函数把这些算法一步一步的实现,使用的时候一个一个的依次调用就可以了。

说明:“面向过程”这个词是在“面向对象”出现之后为与之相对而提出的,它可以看作是“结构化”的别名。

面向对象程序设计

面对日趋复杂的软件系统,结构化程序设计在下面几个方面逐渐暴露出了一些弱点:

  1. 审视问题域的视角。在现实世界中存在的客体是问题域中的主角,所谓客体是指客观存在的对象实体和主观抽象的概念,它是人类观察问题和解决问题的主要目标。例如,对于一个学校学生管理系统来说,无论是简单还是复杂,始终是围绕学生和老师这两个客体实施。结构化设计方法所采用的设计思路不是将客体作为一个整体,而是将依附于客体之上的行为抽取出来,以功能为目标来设计构造应用系统。这种做法导致在进行程序设计的时候,不得不将客体所构成的现实世界映射到由功能模块组成的解空间中,这种变换过程,不仅增加了程序设计的复杂程度,而且背离了人们观察问题和解决问题的基本思路。另外,再仔细思考会发现,在任何一个问题域中,客体是稳定的,而行为是不稳定的。例如,不管是国家图书馆,还是学校图书馆,还是国际图书馆,都会含有图书这个客体,但管理图书的方法可能是截然不同的。结构化设计方法将审视问题的视角定位于不稳定的操作之上,并将描述客体的属性和行为分开,使得应用程序的日后维护和扩展相当困难,甚至一个微小的变动,都会波及到整个系统。面对问题规模的日趋扩大、环境的日趋复杂、需求变化的日趋加快,将利用计算机解决问题的基本方法统一到人类解决问题的习惯方法之上,彻底改变软件设计方法与人类解决问题的常规方式扭曲的现象迫在眉睫,这是提出面向对象的首要原因。
  2. 抽象级别。抽象是人类解决问题的基本法宝。良好的抽象策略可以控制问题的复杂程度,增强系统的通用性和可扩展性。抽象主要包括过程抽象和数据抽象。结构化设计方法应用的是过程抽象。所谓过程抽象是将问题域中具有明确功能定义的操作抽取出来,并将其作为一个实体看待。这种抽象级别对于软件系统结构的设计显得有些武断,并且稳定性差,导致很难准确无误地设计出系统的每一个操作环节。一旦某个客体属性的表示方式发生了变化,就有可能牵扯到已有系统的很多部分。而数据抽象是较过程抽象更高级别的抽象方式,将描述客体的属性和行为绑定在一起,实现统一的抽象,从而达到对现实世界客体的真正模拟。
  3. 封装体。封装是指将现实世界中存在的某个客体的属性与行为绑定在一起,并放置在一个逻辑单元内。结构化设计方法没有做到客体的整体封装,只是封装了各个功能模块,而每个功能模块可以随意地对没有保护能力客体属性实施操作,并且由于描述属性的数据与行为被分割开来,所以一旦某个客体属性的表达方式发生了变化,就有可能对整个系统产生影响。
  4. 可重用性。可重用性标识着软件产品的可复用能力,是衡量一个软件产品成功与否的重要标志。结构化程序设计方法的基本单位是模块,每个模块只是实现特定功能的过程描述,因此,它的可重用单位只能是模块。但对于当前的软件开发来说,这样的重用力度显得微不足道,而且当参与操作的某些数据类型发生变化时,就不能够再使用那些函数了。因此,渴望更大力度的可重用构件是如今应用领域对软件开发提出的新需求。

上述的三个弱点驱使人们寻求一种新的程序设计方法,以适应当代社会对软件开发的更高要求,面向对象由此产生。面向对象技术强调在软件开发过程中面向客观世界或问题域中的事物,采用人类在认识客观世界的过程中普遍运用的思维方法,直观、自然地描述客观世界中的有关事物。面向对象技术的基本特征主要有抽象性、封装性、继承性和多态性。

20世纪80年代,面向对象的程序设计思想开始在业界大行其道,逐渐成为主流。而C++(1983)恰好在这个时期诞生,自然而然地,C++就选择了支持面向对象程序设计的思想。

面向对象是一种思想,它让我们在分析和解决问题时,把思维和重点转向现实中的客体中来,然后通过UML等工具理清这些客体之间的联系,最后用面向对象的语言实现这种客体以及客体之间的联系。它分为面向对象的分析(OOA)、面向对象的设计(OOD)和面向对象的编程实现(OOP)三个大的步骤:

  1. 首先是分析需求,先不要思考怎么用程序实现它,先分析需求中稳定不变的客体都是些什么,这些客体之间的关系是什么;
  2. 把第一步分析出来的需求,通过进一步扩充模型,变成可实现的、符合成本的、模块化的、低耦合高内聚的模型;
  3. 使用面向对象的实现模型。

当我们习惯了面向过程(结构化)编程时,发现在程序过程中到处找不到需要面向对象的地方,最主要的原因,是思维没有转变。程序员通常在拿到一个需求的时候,第一个反应就是如何实现这个需求,这是典型的面向过程的思维方式,而且可能很快就实现了它。而面向对象,面对的却是客体,第一步不是考虑如何实现需求,而是进行需求分析,就是根据需求找到其中的客体,再找到这些客体之间的联系。因此面向过程和面向对象的思维转变的关键点,就是在第一步设计,拿到需求后,一定先不要考虑如何实现它,而是通过UML建模,然后按照UML模型去实现它。这种思路的转变,可能需要个过程。

设计模式

设计面向对象的软件比较困难,而设计可复用的面向对象的软件就更加困难。必须找到相关的对象,以适当的粒度将它们归类,再定义类的接口和继承层次,建立对象之间的基本关系。有经验的面向对象设计者的确能做出良好的设计,而新手则面对众多选择无从下手,总是求助于以前使用过的非面向对象技术。新手需要花费较长时间领会良好的面向对象设计是怎么回事,而有经验的设计者显然知道一些新手不知道的东西,这又是什么呢?
内行的设计者知道,不是解决任何问题都要从头做起,他们更愿意复用以前使用过的解决方案。当找到一个好的解决方案,他们会一遍又一遍地使用。这些经验是他们成为内行的部分原因。

GoF将模式的概念引入软件工程领域,这标志着软件模式的诞生。软件模式并非仅限于设计模式,还包括架构模式、分析模式和过程模式等。实际上,在软件开发生命周期的每一个阶段都存在着一些被认同的模式。软件模式与具体的应用领域无关,也就是说无论从事的是移动开发、桌面开发、Web开发还是嵌入式软件的开发,都可以使用软件模式。
在软件模式中,设计模式是研究最为深入的分支,它融合了众多专家的设计经验,已经在成千上万的软件中得以应用。1995年,GoF将收集和整理好的23种设计模式汇编成了一本名叫《设计模式》的书,该书的出版也标志着设计模式时代的到来。这些模式解决特定的设计问题,使面向对象设计更灵活和优雅,最终复用性更好。他们帮助设计者将新的设计建立在以往工作的基础上,复用以往成功的设计方案。一个熟悉这些模式的设计者不需要再去发现它们,而能够立即将它们应用于设计问题中。
设计模式使人们可以更加简单方便地复用成功的设计和体系结构,将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。设计模式帮助你做出有利于系统复用的选择,避免设计损害了系统的复用性。简而言之,设计模式可以帮助设计者更快更好地完成系统设计。

守破离是武术中一种渐进的学习方法:

  1. 第一步——守,遵守规则直到充分理解规则并将其视为习惯性的事。
  2. 第二步——破,对规则进行反思,寻找规则的例外并“打破”规则。
  3. 第三步——离,在精通规则之后就会基本脱离规则,抓住其精髓和深层能量。

设计模式的学习也是一个守破离的过程:

  1. 第一步——守,在设计和应用中模仿既有设计模式,在模仿中要学会思考。
  2. 第二步——破,熟练使用基本设计模式后,创造新的设计模式。
  3. 第三步——离,忘记所有设计模式,在设计和应用中潜移默化的使用。

当然,如果你不学设计模式,你可能也在无意识的使用一些设计模式,但是这个在跟学过以后再无意识的使用设计模式,应该隔着两重境界吧?

设计原则

我们生活在一个充满规则的世界里,在复杂多变的外表下,万事万物都被永恒的真理支配并有规律的运行着。设计模式也是一样,不论那种设计模式,其背后都潜藏着一些“永恒的真理”,这个真理就是设计原则。的确,还有什么比原则更重要呢?就像人的世界观和人生观一样,那才是支配你一切行为的根本。对于设计模式来说,为什么这个模式是这样解决这个问题,而另一个模式却是那样解决这个问题,它们背后都遵循的就是设计原则。可以说,设计原则是设计模式的灵魂

对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一。在面向对象设计中,可维护性的复用是以设计原则为基础的。每一个原则都蕴含一些面向对象设计的思想,可以从不同的角度提升一个软件结构的设计水平。
面向对象设计原则是对面向对象思想的提炼,它比面向对象思想的核心要素(封装、继承和多态)更具可操作性,但与设计模式相比,却又更加的抽象。形象的讲,面向对象思想类似法理的精神,设计原则类似基本宪法,而设计模式就好比各式各样的具体法律条文。面向对象设计原则是我们用于评价一个设计模式的使用效果的重要指标之一,比如我们在设计模式的学习中,经常会看到诸如“XXX模式符合YYY原则”、“XXX模式违反了ZZZ原则”这样的语句。

对于设计原则,比如SOLID原则和迪米特法则,大家都能耳熟能详,但大多数人对它们的理解都不太深入,笔者建议初学者精读Robert C. Martin在2002年的经典著作《敏捷软件开发—原则、模式与实践》。

领域驱动设计

一直以来,我们按照传统的方式开发软件,如下图所示:

img

tranditional-method.png

分析模型和设计模型的分离,会导致分析师头脑中的业务模型和设计师头脑中的业务模型不一致,通常要映射一下。伴随着重构和bug fix的进行,设计模型不断演进,和分析模型的差异越来越大。有些时候,分析师站在分析模型的角度认为某个需求较容易实现,而设计师站在设计模型的角度认为该需求较难实现,那么双方都很难理解对方的模型。长此以往,在分析模型和设计模型之间就会存在致命的隔阂,从任何活动中获得的知识都无法提供给另一方。

Eric Evans在2004年出版了领域驱动设计(DDD, Domain-Driven Design)的开山之作《领域驱动设计——软件核心复杂性应对之道》,抛弃将分析模型与设计模型分离的做法,寻找单个模型来满足两方面的要求,这就是领域模型。许多系统的真正复杂之处不在于技术,而在于领域本身,在于业务用户及其执行的业务活动。如果在设计时没有获得对领域的深刻理解,没有通过模型将复杂的领域逻辑以模型概念和模型元素的形式清晰地表达出来,那么无论我们使用多么先进、多么流行的平台和设施,都难以保证项目的真正成功。

领域驱动设计分为两个阶段:

  1. 以一种领域专家、设计人员和开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型;
  2. 由领域模型驱动软件设计,用代码来表达该领域模型。

由此可见,领域驱动设计的核心是建立正确的领域模型

领域专家、设计人员和开发人员一起创建一套适用于领域建模的通用语言,通用语言必须在团队范围内达成一致。所有成员都使用通用语言进行交流,每个人都能听懂别人在说什么,通用语言也是对软件模型的直接反映。领域专家、设计人员和开发人员一起工作,这样开发出来的软件能够准确的表达业务规则。领域模型基于通用语言,是关于某个特定业务领域的软件模型,如下图所示:

img

domain-model.png

一个通用领域驱动设计的架构性解决方案包含四个概念层,就是经典的四层模型,如下图所示:

img

ddd-layer.png

  1. User Interface为用户界面/展现层,负责向用户展现信息以及解释用户命令。
  2. Application为应用层,是很薄的一层,定义软件要完成的所有任务。对外为展现层提供各种应用功能(包括查询或命令),对内调用领域层(领域对象或领域服务)完成各种业务逻辑,应用层不包含业务逻辑。
  3. Domain为领域层,负责表达业务概念,业务状态信息以及业务规则,领域模型处于这一层,是业务软件的核心。
  4. Infrastructure层为基础实施层,向其他层提供通用的技术能力;提供了层间的通信;为领域层实现持久化机制;总之,基础设施层可以通过架构和框架来支持其他层的技术需求。

DCI架构模式

James O. Coplien和Trygve Reenskaug在2009年发表了一篇论文《DCI架构:面向对象编程的新构想》,标志着DCI架构模式的诞生。有趣的是James O. Coplien也是MVC架构模式的创造者,这个大叔一辈子就干了两件事,即年轻时创造了MVC和年老时创造了DCI,其他时间都在思考,让我辈望尘莫及。
面向对象编程的本意是将程序员与用户的视角统一于计算机代码之中:对提高可用性和降低程序的理解难度来说,都是一种恩赐。可是虽然对象很好地反映了结构,但在反映系统的动作方面却失败了,DCI的构想是期望反映出最终用户的认知模型中的角色以及角色之间的交互。

传统上,面向对象编程语言拿不出办法去捕捉对象之间的协作,反映不了协作中往来的算法。就像对象的实例反映出领域结构一样,对象的协作与交互同样是有结构的。协作与交互也是最终用户心智模型的组成部分,但你在代码中找不到一个内聚的表现形式去代表它们。在本质上,角色体现的是一般化的、抽象的算法。角色
没有血肉,并不能做实际的事情,归根结底工作还是落在对象的头上,而对象本身还担负着体现领域模型的责任。
人们心目中对“对象”这个统一的整体却有两种不同的模型,即“系统是什么”和“系统做什么”,这就是DCI要解决的根本问题。用户认知一个个对象和它们所代表的领域,而每个对象还必须按照用户心目中的交互模型去实现一些行为,通过它在用例中所扮演的角色与其他对象联结在一起。正因为最终用户能把两种视角合为一体,类的对象除了支持所属类的成员函数,还可以执行所扮演角色的成员函数,就好像那些函数属于对象本身一样。换句话说,我们希望把角色的逻辑注入到对象,让这些逻辑成为对象的一部分,而其地位却丝毫不弱于对象初始化时从类所得到的方法。我们在编译时就为对象安排好了扮演角色时可能需要的所有逻辑。如果我们再聪明一点,在运行时知道了被分配的角色,才注入刚好要用到的逻辑,也是可以做到的。

算法及角色-对象映射由Context拥有。Context“知道”在当前用例中应该找哪个对象去充当实际的演员,然后负责把对象“cast”成场景中的相应角色。(cast 这个词在戏剧界是选角的意思,此处的用词至少符合该词义,另一方面的用意是联想到cast 在某些编程语言类型系统中的含义。)在典型的实现里,每个用例都有其对应的一个Context 对象,而用例涉及到的每个角色在对应的Context 里也都有一个标识符。Context 要做的只是将角色标识符与正确的对象绑定到一起。然后我们只要触发Context里的“开场”角色,代码就会运行下去。
于是我们有了完整的DCI架构(Data、Context和Interactive三层架构):

  1. Data层描述系统有哪些领域概念及其之间的关系,该层专注于领域对象和之间关系的确立,让程序员站在对象的角度思考系统,从而让“系统是什么”更容易被理解。
  2. Context层:是尽可能薄的一层。Context往往被实现得无状态,只是找到合适的role,让role交互起来完成业务逻辑即可。但是简单并不代表不重要,显示化context层正是为人去理解软件业务流程提供切入点和主线。
  3. Interactive层主要体现在对role的建模,role是每个context中复杂的业务逻辑的真正执行者,体现“系统做什么”。Role所做的是对行为进行建模,它联接了context和领域对象。由于系统的行为是复杂且多变的,role使得系统将稳定的领域模型层和多变的系统行为层进行了分离,由role专注于对系统行为进行建模。该层往往关注于系统的可扩展性,更加贴近于软件工程实践,在面向对象中更多的是以类的视角进行思考设计。

DCI目前广泛被作为对DDD的一种发展和补充,用于基于面向对象的领域建模。显示的对role进行建模,解决了面向对象建模中充血和贫血模型之争。DCI通过显示的用role对行为进行建模,同时让role在context中可以和对应的领域对象进行绑定(cast),从而既解决了数据边界和行为边界不一致的问题,也解决了领域对象中数据和行为高内聚低耦合的问题。

面向对象建模面临的一个棘手问题是数据边界和行为边界往往不一致。遵循模块化的思想,我们通过类将行为和其紧密耦合的数据封装在一起。但是在复杂的业务场景下,行为往往跨越多个领域对象,这样的行为放在某一个对象中必然导致别的对象需要向该对象暴漏其内部状态。所以面向对象发展的后来,领域建模出现两种派别之争,一种倾向于将跨越多个领域对象的行为建模在领域服务中。这种做法使用过度经常导致领域对象变成只提供一堆get方法的哑对象,这种建模导致的结果被称之为贫血模型。而另一派则坚定的认为方法应该属于领域对象,所以所有的业务行为仍然被放在领域对象中,这样导致领域对象随着支持的业务场景变多而变成上帝类,而且类内部方法的抽象层次很难一致。另外由于行为边界很难恰当,导致对象之间数据访问关系也比较复杂。这种建模导致的结果被称之为充血模型。

DCI和袁英杰大师提出的“小类大对象”殊途同归,即类应该是小的,对象应该是大的。上帝类是糟糕的,但上帝对象却恰恰是我们所期盼的。而从类到对象,是一种多对一的关系:最终一个对象是由诸多单一职责的小类——它们分别都可以有自己的数据和行为——所构成。而将类映射到对象的过程,在Ruby中通过Mixin;在Scala中则通过Traits;而C++则通过多重继承。

举个生活中的例子:

人有多重角色,不同的角色履行的职责不同:

  1. 作为父母:我们要给孩子讲故事,陪他们玩游戏,哄它们睡觉;
  2. 作为子女:我们则要孝敬父母,听取他们的人生建议;
  3. 作为下属:在老板面前,我们需要听从其工作安排;
  4. 作为上司:需要安排下属工作,并进行培养和激励;

这里人(大对象)聚合了多个角色(小类),在某种场景下,只能扮演特定的角色:

  1. 在孩子面前,我们是父母;
  2. 在父母面前,我们是子女;
  3. 职场上,在上司面前,我们是下属;
  4. 在下属面前,你是上司

对于通信系统软件,没有UI层,应用层也很薄,所以传统的DDD的四层模型并不适用。DCI提出后,针对通信系统软件,我们将DDD的分层架构重新定义一下,如下图所示:

img

ddd-layer-with-dci.png

  1. Schedule是调度层,维护UE的状态模型,除过业务本质状态,还有实现状态。当调度层收到消息后,将委托Context层的Action进行处理。
  2. Context是环境层(对应DCI中的Context),以Action为单位,处理一条同步消息或异步消息,将Domain层的领域对象cast成合适的role,让role交互起来完成业务逻辑。
  3. Domain层定义领域模型,不仅包括领域对象及其之间关系的建模(对应DCI中的Data),还包括对象的角色role的显式建模(对应DCI中的Interaction)。
  4. Infrastructure层为基础实施层,为其他层提供通用的技术能力;提供了层间的通信;为领域层实现持久化机制;总之,基础设施层可以通过架构和框架来支持其他层的技术需求。

领域专用语言

DSL(Domain Specific Language)一般译作领域专用语言或领域特定语言,故名思义,是针对某个特定领域而开发的语言。像我们平时接触到的C、C++和Java等都属于通用语言,可以为各个领域编程,虽然通用性有余,但针对性不强,所以DSL是为了弥补通用语言的这个劣势而出现的。

软件开发“教父”Martin Fowler在2010出版的《领域特定语言》是DSL领域的丰碑之作,掀起来DSL编程的热潮。DSL其实并没有那么神秘。实际上,在平时的面向对象的编程中,大家会自觉不自觉的使用DSL的一些方法和技巧。比如,如果我们定义了一些非常面向业务的函数,然后这些函数的集合就可以被看作一种DSL了。虽然DSL和面向业务的函数之间是有一些类似之处,但这只是问题的一个方面,DSL更多是从客户的角度出发看待代码,定义函数则更多的从解决问题的方案的角度看待代码。诚然两者都有交集,但是出发点却截然不同。
按照Martin Fowler的看法,DSL可以分为两种基本类型,即内部DSL和外部DSL。顾名思义,外部DSL就相当于实现一种编程语言,也许不如实现一门通用语言那么复杂,但是工作量不小;内部DSL就是在一种通用编程语言的基础上进行关键字的定义封装来达到DSL的目的,这种DSL的扩展性可能会受到母语言的影响,对于不熟悉母语言的人来说可能不是那么好理解,不过好处就是你可以利用母语言本身的功能。

袁英杰大师原创的transaction DSL是一种内部DSL(it is C++),用于降低业务的实现复杂度,使得调度层只需处理业务的本质状态,而所有非稳态都是原子的事务过程,如下图所示:

img

transaction-dsl.png

有了transaction DSL之后,针对通信系统软件的DDD四层模型可以演进为五层模型,如下图所示:

img

ddd-layer-with-dci-dsl.png

  1. Schedule是调度层,维护UE的状态模型,只包括业务的本质状态,将接收到的消息派发给transaction DSL层。
  2. transaction DSL是事务层,对应一个业务流程,比如UE Attach,将各个同步消息或异步消息的处理组合成一个事务,当事务失败时,进行回滚。当事务层收到调度层的消息后,委托环境层的Action进行处理。
  3. Context是环境层(对应DCI中的Context),以Action为单位,处理一条同步消息或异步消息,将Domain层的领域对象cast成合适的role,让role交互起来完成业务逻辑。
  4. Domain层定义领域模型,不仅包括领域对象及其之间关系的建模(对应DCI中的Data),还包括对象的角色role的显式建模(对应DCI中的Interaction)。
  5. Infrastructure层为基础实施层,为其他层提供通用的技术能力;提供了层间的通信;为领域层实现持久化机制;总之,基础设施层可以通过架构和框架来支持其他层的技术需求。

微服务架构模式

软件“教父”Martin Fowler在2012年提出微服务这一概念,于是出现了两种服务架构模式,即单体架构模式和微服务架构模式,如下图所示:

img

monoliths-and-microservices.png

微服务是指开发一个单个小型的但有业务功能的服务,可以选择自己的技术栈和数据库,可以选择自己的通讯机制,可以部署在单个或多个服务器上。这里的“微”不是针对代码行数而言,而是说服务的范围不能大于DDD中的一个BC(Bounded Context,限界上下文)。

微服务架构模式的优点:

  1. 微服务只关注一个BC,业务简单
  2. 不同微服务可由不同团队开发
  3. 微服务是松散耦合的
  4. 每个微服务可选择不同的编程语言和工具开发
  5. 每个微服务可根据业务逻辑和负荷选择一个最合适的数据库

微服务架构模式的挑战:

  1. 分布式系统的复杂性,比如事务一致性、网络延迟、容错、对象持久化、消息序列化、异步、版本控制和负载等
  2. 更多的服务意味着更高水平的DevOps和自动化技术
  3. 服务接口修改会波及相关的所有服务
  4. 服务间可能存在重复的功能点
  5. 测试更加困难

尽管微服务架构模式对“个子”的要求比较高,但随着容器云技术的不断成熟,微服务架构模式却越来越火,似乎所有系统的架构都在尽情拥抱微服务,这是不是意味着单体架构模式不再是我们的选择了呢?笔者认为需要根据具体情况而定,我们看看下面这张图:

img

microservice-premium.png

上图直观的说明了单体架构和微服务架构在不同系统复杂度下不同的生产力,以及两者的对比关系。对于那种需要快速为商业模式提供验证的系统,在其功能较少和用户量较低的情况下,单体架构模式是更好的选择,但在单体架构内部,需要清晰的划分功能模块,尽量做到高内聚低耦合。

总而言之,微服务架构有很多吸引人的地方,不过在拥抱微服务之前要认清它所带来的挑战。每一种架构模式都有其优缺点,我们需要根据项目和团队的实际情况来选择最合适的架构模式。

小结

本文较为详细的阐述了软件设计的演变过程,包括结构化程序设计、面向对象程序设计、设计模式、设计原则、DDD、DCI、DSL和微服务架构模式,通过对这些设计思想的全面梳理,可以帮助我们做出更好的设计决策。


软件设计模式——七大设计原则

已剪辑自: https://hjk.life/posts/design-patterns-principles/

  • 概述

    设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结

    描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。

    是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。

    其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性

  • 作用

    • 提高思维能力、编程能力和设计能力。
    • 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期
    • 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强

7种开发原则

开闭原则

  • 定义

    • Open Closed Principle,OCP
    • 软件实体应当对扩展开放,对修改关闭。即, 当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。
  • 作用

    • 软件测试的影响

      测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。

    • 提高代码的可复用

      粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。

    • 提高软件的可维护

      稳定性高和延续性强,从而易于扩展和维护。

里氏替换原则

  • 定义
    • Liskov Substitution Principle,LSP
    • 继承必须确保基类所拥有的性质在子类中仍然成立。即, 子类可以扩展父类的功能,但不能改变父类原有的功能。
  • 作用
    • 是实现开闭原则的重要方式之一。
    • 克服了继承中重写父类造成的可复用性变差的缺点。
    • 类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。

依赖倒置原则

  • 定义
    • Dependence Inversion Principle,DIP
    • **要面向接口编程,不要面向实现编程。**即, 高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
  • 作用
    • 可以降低类间的耦合性
    • 可以减少并行开发引起的风险。
    • 可以提高代码的可读性和可维护性。

单一职责原则

  • 定义
    • Single Responsibility Principle,SRP
    • 单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。
    • 如果一个对象承担了太多的职责,至少存在以下两个缺点
      • 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力;
      • 当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。
  • 作用
    • 降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。
    • 提高类的可读性。复杂性降低,自然其可读性会提高。
    • 提高系统的可维护性。可读性提高,那自然更容易维护了。
    • 变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。

接口隔离原则

  • 定义
    • Interface Segregation Principle,ISP
    • 客户端不应该被迫依赖于它不使用的方法
    • 一个类对另一个类的依赖应该建立在最小的接口上
    • 与单一职责原则的区别
      • 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。
      • 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。
  • 作用
    • 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
    • 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。
    • 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。
    • 减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。

迪米特法则

  • 定义
    • Law of Demeter,LoD, 又叫作最少知识原则Least Knowledge Principle,LKP)
    • 如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
  • 作用
    • 降低了类之间的耦合度,提高了模块的相对独立性。
    • 由于亲合度降低,从而提高了类的可复用率和系统的扩展性。

合成复用原则

  • 定义

    • Composite Reuse Principle,CRP, 又叫组合/聚合复用原则Composition/Aggregate Reuse Principle,CARP)。
    • 在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
  • 作用

    • 通常类的复用分为

      继承复用

      合成复用

      两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点:

      • 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
      • 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与
      • 限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。
    • 采用组合或聚合复用时,可以

      将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能

      ,它有以下优点:

      • 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
      • 新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口
      • 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。

总结

设计原则一句话归纳目的

开闭原则对扩展开放,对修改关闭降低维护带来的新风险
依赖倒置原则高层不应该依赖低层,要面向接口编程更利于代码结构的升级扩展
单一职责原则一个类只干一件事,实现类要单一便于理解,提高代码的可读性
接口隔离原则一个接口只干一件事,接口要精简单一功能解耦,高聚合、低耦合
迪米特法则不该知道的不要知道,一个类应该保持对其它对象最少的了解,降低耦合度只和朋友交流,不和陌生人说话,减少代码臃肿
里氏替换原则不要破坏继承体系,子类重写方法功能发生改变,不应该影响父类方法的含义防止继承泛滥
合成复用原则尽量使用组合或者聚合关系实现代码复用,少使用继承降低代码耦合

实际上,这些原则的目的只有一个:降低对象之间的耦合,增加程序的可复用性、可扩展性和可维护性。

记忆口诀:访问加限制,函数要节俭,依赖不允许,动态加接口,父类要抽象,扩展不更改。

在程序设计时,我们应该将程序功能最小化,每个类只干一件事。若有类似功能基础之上添加新功能,则要合理使用继承。对于多方法的调用,要会运用接口,同时合理设置接口功能与数量。最后类与类之间做到低耦合高内聚。

参考


软件设计方法

已剪辑自: https://www.cnblogs.com/bastard/archive/2011/11/30/2269587.html

(软件)设计方法 装载自:http://www.chinaunix.net/jh/28/70767.html
作者:Larry Brinn 翻译: CKER
\1. 简介
\2. (软件)设计是什么?
\3. (软件)设计过程
\4. (软件)设计基础
\5. (软件)设计方法论
\6. (软件)设计文档
\7. 面向对象的(软件)设计
\8. 结论

一 简介

1您是如何开始一个新工程的?是不是跳到计算机前,打开您喜爱的 RAD 工具开始输入代码?

2有没有想过程序会执行些什么或者系统是如何操纵数据的?

3有没有想过要记下些东西来帮助提醒您或阐明您已经开发的代码的逻辑实现?如果您对第一个问题答"不",而其他问题答"是"的话,您可以跳过这篇文档。否则的话,请好好读读 这篇文章。

您应该有个计划、蓝图,并且在手边有个对您的问题解决方案的简明安排。您必须知道您要去哪儿得到一切!让我们来看看开发一个能实现您所设计的功能的程序时,什么最棘手。

二(软件)设计是什么?

E.S. Taylor 给设计下的定义是 :
" …the process of applying various techniques and principles for the purpose of defining a device,

a process or a system in sufficient detail to permit its physical realization. "
" … 应用各种各样的技术和原理,并用它们足够详细的定义一个设备、一个程序或系统的物理实现的过程。 "

对任意的工程产品或系统,开发阶段绝对的第一步是确定将来所要构建的制造原型或实体表现的目标构思

这个步骤是由多方面的直觉与判断力来共同决定的。

这些方面包括构建类似模型的经验、一组引领模型发展的原则、一套启动质量评价的标准、以及重复修改直至设计最后定型的过程本身。

计算机软件设计与其他工程学科相比还处在幼年时期,仍在不断变化中,

例如更新的方法、更好的算法分析、以及理解力的显著进化。软件设计的方法论的出现也只有三十年多一点,

仍然缺乏深度、适应性和定量性质,通常更多的与经典工程设计学科相联系。

尽管如此,现今的软件技术已经存在、设计质量的标准也可使用、设计符号亦可以应用。

带着这些意见,我们一起来看看什么有助于程序员们找到他们的软件涅盘 ( 天堂的意思 ) 。

三 设计过程

软件的设计一个将需求转变为软件陈述(表达)的过程。这种陈述给我们一个对软件的全局观点。

系统通过逐步求精使得设计陈述逐渐接近源代码。这里有两个基本步骤;

第一步是 初步设计 Preliminary design ,关注于如何将需求转换成数据和软件框架。

第二步是 详细设计 Detail design ,关注于将框架逐步求精细化为具体的数据结构和软件的算法表达。

发生中的设计行为、数据、算法和程序设计都需要由现代程序所需的界面设计这一清晰的行为来结合起来。

界面设计 Interface design 建立程序布局和人机交互机制。

贯穿设计过程的质量由一系列的 正式技术评定 formal technical reviews 或 设计排演 design walkthroughs 来评价。

良好的设计规范必须建立在对设计陈述(表达)的评估之上,以下是一些指导方针:

\1. 设计应该展现层次结构使得软件各部分之间的控制更明智。

\2. 设计应当模块化;这就是说,软件应在逻辑上分割为实现特定的功能子功能的部分。

\3. 设计应当由清晰且可分离的数据过程表达来构成。

\4. 设计应使得模块展现独立的功能特性。

\5. 设计应使得界面能降低模块之间及其与外部环境连接复杂性

\6. 设计应源自于软件需求分析期间获得的信息所定之可重复方法的使用。

要拥有良好的设计特征不是靠碰运气,而在设计过程中通过综合运用基础设计原理系统方法论彻底的评定回顾可以有助于良好的设计。

软件设计方法每天都在进化,作为已经经过测试和细化的方法,良好的设计应具有以下的四种特性,并在所有这些特性之间保持一致。

\1. 将信息领域的表达转换为软件设计的表达的机制。

\2. 表示功能组件及其界面的符号

\3. 逐步求精分割的试探

\4. 质量评估的指导方针。

开发软件的时候,不管采用何种设计方法您必须能够熟练运用一套关于数据算法和程序设计的基本原理

四(软件)设计基础

软件设计方法论的这套基本原理已经经过了多年的进化。每种概念的影响程度不尽相同,但它们都经历了时间的洗礼。

基于这些基本原理设计者可以采用更多更成熟的设计方法。这些基本原理有助于设计者回答以下的问题:

\1. 将软件分割成独立的组件时会采用何种标准?

\2. 怎样将软件的原则性表示详细分割成函数或数据结构?

\3. 有没有定义一个软件设计的技术质量的统一标准?

M.A. Jackson 曾经说过: " 对一个计算机程序员来说,分辨让程序运行和让程序 正确 之间的差异是一个良好的开端。

" 为了 " 使程序 正确 " ,基本设计原理提供了必须的框架。因此让我们来对这些基本原理作个简短的检视。

1****抽象 Abstraction

在最高层次上指的是使用待解决的问题领域内的术语描述的解决方案。相对较低层次的抽象则更多的面向程序语言,

最低层的抽象则是解决方案的可直接实现的方式描述。软件设计的每一个步骤都是对相应层次解决方案的抽象的逐步求精。

2****求精 Refinement

又叫做逐步求精指的是通过程序细节连续细化来开发程序体系的策略。

分步骤的对程序抽象进行分解直至成为编程语言的过程同时造就了程序的层次结构。在这一点上要对细节多做考虑,这也展示了求精实际上是个苦心经营的过程。

3模块化 Modularity

指的是软件可被分割为分别命名并可寻址的组件(也叫做模块),将模块综合起来又可以满足问题的需求的性质。

" 软件的模块化是允许智能化管理程序的唯一属性。 " 换句话说,当您将一个复杂问题分解为一些小问题时会更容易解决。

需要重点解释的是即使一个系统必须象 " 单片机 " 一样来实现,它也可以采用模块化设计。

4****软件体系(架构) Software Architecture

涉及到程序的两个重要特性: 1) 模块的层次结构。 2)数据结构

这源自于需求分析时将真实世界问题的含蓄定义与软件解决方案的要素关联起来的分割过程。

当问题的每个部分通过一个或多个软件要素得到解决后,与问题的定义和解决相一致软件和数据结构的进化就开始了。

这个过程代表了软件的需求分析和设计之间的位置。

5****控制层级 Control Hierarchy

也称作程序结构,描述程序组件的组织并意味着控制层级。

它并不描述软件的程序方面,比如进程顺序、决定的事件 / 命令、或工作循环。

如下的层级图表展示了模块之间的通信流,并显示哪些模块是重复的(右上角变黑的块)。

这个图表描述了一个能够读文件,计算每个记录的值并书写报表来显示记录的信息和所完成的计算。

6****数据结构 Data structure

描述了单个数据间的逻辑关系。数据结构规定了数据的组织、访问方法、关联程度、和信息的选择处理。

数据结构的组织和复杂性只受限于设计者的灵活性。唯一的限制就是经典数据结构的数量阻碍了更多的久经考验的结构出现。

7****软件程序 Software Procedure

着重于处理每个模块的细节并必须提供一个精确的处理规范,包括事件顺序、准确的判定点重复操作、甚至数据结构

软件的程序表现是分层的,处理方法应该包括其所有子模块的参考。

8****信息隐藏 Information Hiding

的法则建议 由设计决定所刻划的模块特性应该对其余的模块不可见

换句话说,模块应被设计和指定为包含在模块内部且其他模块不可访问的内容对其他模块来说是无需的。

隐藏意味着有效的模块性能够通过定义一套独立的模块来实现,这些模块相互之间的通信仅仅包括实现软件功能的所必须的信息。

将使用信息隐藏作为设计标准在测试或今后的维护期间需要修改系统时带来了最大的好处。

五(软件)设计方法论*

让我们来遍历设计过程中用以促成模块化设计的四个区域: 模块 Modular数据 Data体系 Architectural程序 Procedural 设计。

模块设计 Modular design 减低了复杂性、便于修改、且使得支持系统不同部分的并行开发实现起来更容易。

模块类型提供的操作特性通过结合时间历史激活机制、和控制模式来表现。在程序结构内部,模块可以被分类为:

\1. 顺序 sequential 模块,由应用程序引用和执行,但不能从表观上中断。

\2. 增量 incremental 模块,可被应用程序先行中断,而后再从中断点重新开始。

\3. 并行 parallel 模块,在多处理器环境下可以与其他模块同时执行。

单独的模块更容易开发,因为功能可以被划分出来,而界面只是用来确保功能的独立。

功能的独立性可以使用两个定性的标准来衡量: 凝聚性 cohesion -衡量模块的功能强度的相关性,和 耦合性 coupling -衡量模块间的相互依赖的相关性。

数据设计 Data design 首先并且有些人也坚信,是最重要的设计行为。

数据结构的影响和程序上的复杂性导致数据设计对软件质量有着深远的影响。这种质量由以下的原理来实施:

\1. 适用于功能和行为分析的系统分析原理同样应该适用于数据。

\2. 所有的数据结构,以及各自所完成的操作都应该被确定。

\3. 创建数据词典并用来详细说明数据和程序的设计。

\4. 底层的数据设计决定应该延迟至设计过程的后期。

\5. 数据结构的陈述(具体说明)应该只被那些直接使用包含在此结构内的数据的模块所知道。

\6. 有用的数据结构和操作库可以在适当的时候使用。

\7. 软件设计和编程语言应该支持抽象数据类型的规范和实现。

体系设计 Architectural Design 的主要目标是开发模块化程序结构并表达出模块间的控制相关性

另外,体系设计融合了程序结构与数据结构,以及使得数据得以在程序中流动的界面定义。

这种方法鼓励设计者关注系统的整体设计而不是系统中单独的组件。

选用不同的方法会采用不同的途径来接近体系的原点,但所有这些方法都应该认识到具有软件全局观念的重要性。

程序设计 Procedural Design 在数据、程序结构、和陈述详细算法的说明都已使用类似英语的自然语言来呈现后,再确定程序设计。

使用自然语言来陈述的原因是当开发小组的绝大多数成员使用自然语言来交流的话,

那么小组外的一个新手在不经学习的情况下会更容易理解这些说明。

这里有个问题:程序设计必须毫无歧义的来详细说明程序,但我们都知道不含糊的自然语言也就不自然了。

六(软件)设计文档

在任何系统中,开发文档都是有价值的东西。现在已经有许多不同的经过发展的文档计划可供您在创建系统时候进行选择。

其中相当不错的一种模型就是所谓的设计规范 (译者注:此处原有的超链接已经失效,所以无法得到其原始的模板。

但 CKER 还有一套被称作的 APM 的文档模板似乎不错。以后也许会翻给大家来看看 ……_ ) 。

当您察看此文档的大纲的时候 , 请注意各级别的详细内容。

第一部分展示了源自于系统说明和其他定义文档的设计成果的总体范围。

第二部分展示的是涉及支持文档的详细说明。第三部分的内容又称作设计描述,在初步设计阶段完成。

第四、五部分的内容将初步设计阶段的内容发展至详细设计阶段。第六部分展示了确保以下两条原则的交叉参考矩阵:

\1. 用软件设计满足所有的需求。

\2. 指出实现特定需求的关键模块

第七部分在开发测试程序(步骤)的第一步对系统的功能性和正确性进行测试是必要的。

如果在开发设计规范的同时已经并行开发了详细的测试程序规范的话,本部分可以删除。

第八部分详细说明了将系统打包传送至用户站点的考虑和要求。

在文档剩下的第九、十部分中包括了算法描述、选择程序、列表数据、流程图、伪代码、数据流图表、以及所有在设计规范开发时所用到的相关信息都可以放在此处。

七 面向对象的(软件)设计

到目前为止我们所详细说明的一切都是如今在 IT 领域被广泛使用的设计方法论的基石。

面向对象的设计( OOD )通过模块化信息及其加工方法而不单单是加工方法来让数据对象和加工操作得以互相连接。

这个过程依赖于三个极其重要的设计概念:抽象信息隐藏、和模块化。所有的设计方法都力争展现这些特性;

但只有 OOD 的机制才能使设计者能够无需增加复杂性或加以折衷就获得所有三种特性。

在 OOD 中,我们有 objects (对象) , operations (操作) ,和 messages (消息) 。

Objects (对象 ) , 又称作类,可以是人、机器、命令、文件、汽车、房子,等等。 operations (操作) ,

包含了私有的数据结构和用于变换数据结构的加工方法。 messages (消息) 用于激活调用操作控制和对象的程序构造。

这就是说对象的共享部分是其的接口而消息在接口之间移动并指定希望使用对象的何种操作,

但并不知道操作是怎样具体实现的。对象在收到消息之后决定如何来执行消息。

现在让我们来看看在面向对象的系统中的某些工具是如何使用的:

1. 伪代码 - 接近计算机编程语言的指令,但使用的是近似英语的语言而不是真正的编程语言以便于查看程序逻辑。

下面是一个加工文件中的记录的范例 :

Start ( 开始 )

Initialize program ( 初始化程序 )

Read a record ( 读一个记录 )

Process record ( 加工记录 )

Move record to print area ( 将记录移至打印区 )

Write a line ( 写一行 )

End job ( 结束任务 )

Stop run. ( 停止运行 )

2. 原型 - 在开发软件包的第一个版本或模型,或者计算机硬件准备好作生产前测试时的步骤。

通常可以使用您所喜爱的 RAD 工具来创建。

3. TOE 图表

(Task 任务 , Object 对象 , Event 事件 图表 ) 用来展示需要完成的任务或工作、执行工作的对象、以及完成此过程的事件或动作。请看下面将两个数相加的 TOE 图表:

任务 对象 事件

启动程序 Main Form OnStartup

输入第一个数 EdtFirstNumber User types in

输入第二个数 EdtSecondNumber User types in

求和 EdtResult OnClick

程序退出 BtnExit OnClick

正如您在上例中所见,这正确说明了要执行什么、谁来执行、以及什么时候来执行。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小熊coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值