精华内容
下载资源
问答
  • 本文分享阿里资深技术专家六铢的架构方法论,这套方法论中包含了详细的架构推导逻辑,希望能够帮助大家在工作中从各个粒度、各个层次来做好架构工作。较长,同学们可先收藏再看。 一、背景 1.1 架构中的问题识别 ...

    Blog: https://blog.yilon.top

    作者: 阿里技术

    地址: https://zhuanlan.51cto.com/art/202004/613905.htm

    本文分享阿里资深技术专家六铢的架构方法论,这套方法论中包含了详细的架构推导逻辑,希望能够帮助大家在工作中从各个粒度、各个层次来做好架构工作。较长,同学们可先收藏再看。

    一、背景

    1.1 架构中的问题识别

    需求分析,架构实现,(新需求,架构改动)* n = 推倒重来。

    这个过程是一个循环往复的过程,有的产品每年都会推倒重来一次。

    而这个过程是如何造成的呢?原因之一是每次迭代过程中都没有用正确的架构方法来进行迭代造成的,就像在歪楼上继续加盖楼层一样,最终还是会倒塌(不过这个原因并不是唯一的原因,其他原因留到后续文章中阐述)。

    这真是一个悲伤的故事,但是又是一个时常发生的故事。或者说我们大多数人都经历过的场景。

    要解决这个问题,那就需要在每次迭代中,都需要用正确的姿势对不对?要用对姿势其中有一个重要的原因是架构。就像一幢大楼,架构设计得越有问题,这幢大楼被重造的可能性就越大。

    这里正确的姿势到底是什么姿势?接下来本文会阐述一整套架构方法论,该方法论中包含了详细的架构推导逻辑,帮助我们在工作中在各个粒度,各个层次做好架构工作。

    我们后续的文章中将会着重阐述如何通过自底向上以及自顶向下的两种架构思考方式来解决这些问题,但是在那之前,我们还是先来聊聊什么叫“架构”。

    1.2 什么是架构?

    大概是在 11 年前左右,在土豆网做广告平台,同时也做视频 CDN 的相关事情,当时做一个服务,基础架构是 lighttpd + squid + tomcat,将静态资源分离到 httpd,get 请求使用 squid 缓存,智能路由使用 HTTP post 请求,并让 tomcat 提供服务,当时就觉得这就是架构。再后来,做了视频 CDN 相关的基础建设的工作,就觉得这就是做架构,关键那个时候也没有人告诉我们什么架构,自己不知道自己不知道。

    再后来慢慢成长,又去做了几年中间件(包括高性能 RPC 和 JSR-170),然后就觉得这也是做架构。当时也没有前辈跟我讲什么是架构,那个时候的我对架构是没有体系化认知的,都是凭着感觉做的,是不知道自己不知道。

    再后来,来到了阿里做应用研发和架构了,发现业务开发中也包含了各种方法论,而以前看过的建模相关的资料,在中间件等基础设施上也没有太大的感觉,反而在业务技术领域发挥出了巨大的光芒。也发现越靠近用户的架构,随着企业的慢慢壮大会变得越来越重要。这个时候的我对架构认知是知道自己不知道了。

    既然知道自己不知道了,那么就是要追寻它,曾经我和不少业务的研发同学讨论过架构是什么,撇去基础设施架构和物理架构等视角不谈(这些视角聊起来也是篇幅很长的),我挑应用逻辑架构并从几个角度来尝试描述一下:

    1)从架构的总原则的角度:尽可能简单(在当前场景下要尽可能简单便于扩展和维护),但是不能太简单(相对而言太过于简单可能在场景上有所遗漏).

    2)从架构的目的角度来考虑:既要解决过去的问题,也要解决现在的问题,还能适度解决未来的问题,这些问题既包含技术问题,更包含业务问题。

    3)从形态之 2 维的角度来考虑:架构就是横的问题,和竖的问题。横就是分层,竖就是分区,横竖都有抽象的事情要做。

    4)从形态之 3 维的角度来考虑:架构是三维的,在 x 轴和 y 轴上有横竖的问题,在z轴上还有粒度的问题。

    5)从时间轴的角度来考虑:架构不是一层不变的,是随着业务的发展在不断变化的。

    可以看出,虽然我试图从以上几个视角对架构进行了描述,但是显然这些描述都是见仁见智的观点,是从某个角度来看架构。内心里我觉得自己提炼的高度是不够的,实践中的总结必须和业界的知识结合起来,我必须学习前人已经总结的体系。于是在不断的搜集资料的过程中,我发现在 ISO/IEC 42010:20072 中对架构有如下定义:

    The fundamental organization of a system, embodied in its components, their relationships to each other and the environment, and the principles governing its design and evolution.

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QioMrOeP-1586353450968)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/30a89a2dadc322ab13207c5d853fdab1-20200408104453569.jpg)]

    这个最顶层抽象我个人觉得非常到位,根据这个定义,显然,我们在架构中需要:

    • 职责明确的模块或者组件
    • 组件直接的关联关系非常明确
    • 需要有约束和指导原则

    这个架构的定义很简练,很实在。小到一个玩具,大到一个国家的运作都可以隐含着这样的内容。

    但这是一个广义上定义的架构,经过一些总结思考,我觉得实际上具体到我们日常的工作中,在不同的层次,会有更加精细化的架构分类。

    1.3 架构有哪些分类

    在工作中我遇到不同职位的人从不同的角度来描述架构,但是我们鲜有能达成共识的,刚开始我也不知道为啥讨论不到一块去,后来经过一段时间的纠结和深入仔细的思考后,我发现很多时候大家描述的架构都不是同一个角度的东西,于是我尝试从如下几个角度划分架构的类别,以帮助我们在不同的场景和不同的人聊天时大家可以聚焦,明确我们到底是在讨论哪种架构,以提升沟通效率,并尽快达成共识,目前这个划分已经在我们团队基本达成共识。

    值得注意的是,不管下面哪种分类的架构,都符合上一节总的架构的定义:模块(组件)+ 关系 + 约束 & 原则。

    1. 产品功能架构

    这个是产品经理最喜欢讲的架构,一般来说,讲我们有什么功能的时候,产品功能架构描述的是能做什么,受众群体一般是使用产品的同学。如果我们做软件设计时,不应该产出这玩意,而是应该产出应用逻辑架构和应用物理架 构。但是一旦我们要对外宣讲我们的产品,比如我们的接口有啥用,应该怎么用,这个时候我们讲的应该是产品功能架构。

    • 目的:指导用户使用产品,所以模块的聚合是从用户视角出发的
    • 受众:使用产品的人
    • 包含的内容:阐述产品功能模块的能力:比如一辆汽车,方向盘有什么功能,方向盘的按钮上各区域的功能是什么,仪表盘分成哪些功能模块,每个功能模块有什么作用,油门踏板有什么作用,刹车踏板有什么作用。但是也不排除有些高阶用户需要明确知道变速箱的齿比等信息,所以在产品功能架构图上也可以描绘出来。
    • 命名:这里命名需要考虑如何取一个吸引人的名字(同时又能表达产品的能力)来吸引我们的用户前来使用,比如说以前经常有产品套用“纳米”,又有产品套用“绿色”等等。

    2. 业务能力架构

    用来分析业务,业务概念架构是指拥有哪些业务模块,且各自的能力是什么,这张图有助于我们分析和理解业务需求,也有利于产品经理分析业务。所以业务概念架构和业务概念模型都是用在分析阶段。

    • 目的:研发人员和业务人员理解业务内在的概念和联系。
    • 受众:研发人员和业务人员,主要是给规划业务的人使用。
    • 包含的内容:业务能力,能力中的子能力。

    3. 应用逻辑架构

    软件设计本身,模块,粒度,职责,复用,等等,在讲解软件设计的时候,使用的是这个架构图,这个架构图是通过系统模型和业务概念架构推导而来。所以系统模型和应用逻辑架构都是用在软件设计阶段。

    • 目的:指导软件的研发。
    • 受众:研发人员,各层级架构师,各层级技术管理者。
    • 包含的内容:阐述架构中各模块的职责:如系统模型,技术模块,技术模块的关系,技术模块的核心抽象,如何用设计模式来让架构符合软件设计原则,等等。如果拿汽车举例,那就是发动机模块中包含了哪些子模块(活塞,曲轴,连杆,缸体,缸盖,等等)发动机模块和变速箱模块之间的关联关系是什么,如何协同工作,和底盘的关联关系是什么,如何协同工作。发动机,底盘,变速箱,电子系统在整辆汽车中的职责,关系,约束是什么。这些都是用来指导汽车研发的。而不是指导用户如何使用这辆汽车的。
    • 命名:这里的命名需要朴实无华,精准的描述出职责,华而不实反而让技术的同学无法理解这到底是什么玩意,导致实施的时候职责放错地方,挖下大坑让后人来填。

    4. 应用物理(部署)架构

    软件部署时的架构,这张图推导自应用逻辑架构,推导时重点逻辑架构如何落地,比如使用何种微服务容器,逻辑架构的模块落地时应该是 package,还是应用,也有可能是一组应用,是不是要跨机房部署,甚至跨国部署等等。还需要考虑稳定性,性能,成本等话题。

    5. 基础设施架构

    选择什么样的中间件,存储,监控,报警,等等。

    6. 等等

    1.4 能力和职责的区别

    在日常的架构讨论中,有的同学经常谈架构的能力,有的同学经常谈架构的职责,那么能力和职责有什么区别?跟产品的同学打交道多了之后,发现产品同学很多都是讲能力,后来技术的同学也开始讲能力,而通常我们架构的同学原来讲的都是职责,两者有什么区别呢,我说说自己的理解:

    1. 能力(产品功能模块的能力)

    是指一个产品能做什么,比如中台本身是一个产品,对使用中台的同学来说,我们应该讲中台的能力(其实是在讲中台这个产品的能力)。所以讲能力是讲给架构的使用者或者其他想了解的人来听的。

    2. 职责(逻辑架构中各模块的职责)

    是指架构内模块的职责,用来指导开发,比如中台研发的同学,应该讲架构的职责,依赖,约束。所以讲职责是讲给研发的同学,讲给域内的架构师,讲给域内的管理者来听的,总的来说就是讲给架构的实现者来说的。

    简单来说就是:能力是指产品的能力,职责是指架构内部的职责。如果架构本身也是一个产品需对外输出(如中台,或者其他技术框架作为产品输出),则对外输出时,我们应该讲这个技术产品的能力(这个时候技术的同学也就开始讲能力了)。所以当我们讨论问题的时候,如果有的人在谈产品能力,有人在谈架构内部职责,那么显然已经不是在讨论同一个话题了,请大家务必注意区分这种情况,差之毫厘,谬以千里,鸡同鸭讲啊。

    比如说两个模块 A 和 B,职责不一样,但是依赖了相同的二方库。那我们不能说某个职责在这个二方库里。这个二方库作为某个独立的技术小产品,提供了某些能力。但是履行职责的还是 A 模块或者 B 模块。

    1.5 应用逻辑架构的地位

    正如前面我们描述的架构分类所描述,有些架构和具体业务是无关的,有些架构是和具体业务息息相关的,比如说应用逻辑架构就是和业务息息相关,它来源于业务的抽象,甚至我们可以说:它是业务线技术架构设计中第一份产出。

    既然他是首要的产出,我们就必须要考虑应用逻辑架构中应该包含的三类主题:

    • 模块

    • 依赖

    • 约束

    绝大部分的架构问题都可以归纳成这三类主题,这些主题包含哪些内容呢?这就是本文接下来要介绍的内容,应用逻辑架构的设计不需要拍脑袋,是通过科学的方法体系推导出来的。

    二、架构的两种推导思路

    架构的产出总的来说有两种方式,一种是自顶向下的方式来推导架构,一种是自底向上的推导方式,而且两种方式往往是相互结合来产出最合适的结果。而在业务线的同学,可能接触最多的是自底向上的推导的方式,自底向上的推导的方式也是本文中要重点讲解的架构推导方式。

    2.1 自顶向下的架构推导

    自顶向下的推导的关键问题在问题定义,如果问题没有被准确的定义,那么自顶向下就无法推导出正确的结果。假设问题被准确的定义了,如何自顶向下推导呢?

    2.2 自底向上的架构推导

    我们在业务线做开发的同学,每天肯定跟很多需求打交道,这些需求哪里来的?基本上有这三种产出:

    1. 有些是来自产品方一拍脑袋产生的灵感
    2. 有些是对数据进行了详细的分析产出的产品策略
    3. 有些是当前产品中暴露的一个个问题

    产品方的这些详细的需求来了之后,我们是如何应对的呢?我们首先和产品方一起讨论产品方案的合理性,在产品方案合理的基础上,我们来开始识别用例,开始了一系列软件工程领域方面的措施。其整体过程如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b7ohBB5o-1586353450968)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/cefa83dd2885374537919ba0f4beff7b.jpg)]

    自底向上推导逻辑架构就是最右边代表的那条曲线。

    这里基本上就是本文接下来要重点阐述的:如何自底向上推导应用逻辑架构,这个过程就是一个抽象和架构的过程。

    那么我们从整体方法论的介绍开始,采用总分总的结构,下面这张图就是应用逻辑架构自底向上的推导路径,这个推导路径是有序的,每个步骤都包含了大量的操作技巧,前一步做好,后一步才有可能得出正确的结果。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VsV9yx19-1586353450969)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/dda5ae5963e720aefff8889bf2aeec7f.jpg-wh_600x-s_1586740766-20200408104453570.jpg)]

    这张图中有几个重点:

    1)软件研发分成了两个阶段:

    • 分析阶段,也是我们常说的问题空间领域建模,关键的一步是业务概念模型的输出,而业务概念模型输出的前置条件是从需求中分解出合理的用例集合。
    • 设计阶段,也是我们常说的解决方案空间建模,以及应用逻辑架构。

    2)图中存在了箭头这个东西,说明了我们做架构推导的主要的思维路径,也说明做架构不需要拍脑袋,都是根据严密的逻辑推导出来的。

    这个严密逻辑基本是一个自底向上的推导过程,底层的模型是通过建模方法演绎出来,逻辑架构中的各个模块是通过归纳的方法推导出来。那么:

    • 什么地方应该用演绎,什么地方应该用归纳呢?
    • 使用演绎的时候应该使用何种具体方法呢?
    • 使用归纳的时候应该使用何种具体方法呢?

    我们再留一个悬念,后面再讲。

    不管是演绎还是归纳,都是抽象工作的一部分,而且都需要素材,这里的素材就是我们对需求,对业务的理解,以及对技术的深度广度的把握。没有素材,方法论掌握再好也得不出结果。

    素材哪里来呢?

    业务素材的来源大部分是你需要解决问题所在的领域,比如我们在电商领域,那么我们就要多搜集电商领域的业务知识。如果我们在数据领域,自然要多搜集数据业务的相关知识,以及我们前文中讲到的技术类的相关知识。

    而技术素材是要求我们在技术领域不断的钻研,不断的扩展边界,深度不断增加,广度也不断增加。所以对于架构师来说计算机科学与技术是绝对要不断精进的。

    2.3 两个方法的区别

    自顶向下推导的一个前置条件就是你需要知道猪长什么样,在架构上就是你需要知道这个架构的原来是是什么样子的,解决什么问题的。如果都不知道猪长什么样,那么就无从判断猪是不是适合当宠物了。此处需要有一定的业务领域理解力和领域经验(包含:客户的问题和痛点是什么,怎么分析出来的,当前的架构方案是什么,当前的架构方案是如何解决这个问题的,未来的架构方案如何更好的解决这个问题)。

    而自底向上推导则没有这个问题,因为是看着猪来做推导的,知道猪的细节,这个细节的特点如何演绎,如何归纳,最后得出结论。

    所以当我们不熟悉一个大的业务的时候,我们自顶向下推导架构的难度是极大的,几乎不能完成。不了解业务或技术情况时定义出来的问题也未必是一个被正确定义的问题,容易给人造成一个印象:瞎指挥。

    这个时候如何在没有知识背景的情况下快速落地就得自底向上的来推导架构。在自底向上的过程中慢慢熟悉业务。

    但是如果工作中每每都是纯粹的自底向上的推导架构,是无法帮助我们来做技术的前瞻性布局的,此时架构师的成长就遇到的瓶颈,所以此时又要使用自顶向下的架构推导方式。

    综上所述,不管是自底向上,还是自顶向下,都是架构师需要掌握的技能。

    三、自底向上的架构方法:业务概念架构推导

    这部分内容,我在 ICBU,村淘,一达通,菜鸟,AE 现场分享过。尤其是在 AE,一达通和菜鸟,相关的同学都拿出了当时的纠结大家很久的难题,我们一起使用了这样的方法很快就分析出了业务概念模型,并且对模块进行了简要的划分,形成概要的业务概念架构。经过大量的实战,效果是非常明显的。

    3.1 模型的 3 个层次

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yvdF2Kdg-1586353450970)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/a6a4083efe4266ee863098f56c6aef31.jpg-wh_600x-s_1850283332-20200408104453567.jpg)]

    在这里,我把一些常见的概念集中起来,便于大家统一概念:

    1. 业务概念模型,问题空间领域模型,信息模型是同样的意思,这个层次上的实体我们称之为概念实体,这部分内容是用在需求和业务分析上的,讨论业务概念模型时完全不需要考虑软件的实现,这个过程是一个分析过程,即使不做软件研发,做其他的研发,类似的分析过程也应该是有的。

    2. 系统模型,解决方案空间领域模型,逻辑模型是同样的意思,这个层次上的实体,我们称之为系统实体,或者逻辑实体,就是各种类,这个是用在软件设计和软件研发上的。

    3. 存储模型,数据模型,物理模型,在这里也是同样的意思,这个层次上的实体,我们称之为数据实体,或者物理实体,也是用在软件设计上。

    这 3 个层次其实是从 3 个角度在看待问题,他们之间是自上而下的转换的关系,这里尤其要注意的两个词是:逻辑的,顺序的推导。

    这些不同层次的模型是应用逻辑架构的基础!!!

    3.2 模型的推导

    3.2.1 用例集合推导概念模型

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AhCIJTUB-1586353450970)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/db18d4f9913f2302dc5931958da18828-20200408104453581.png)]

    1. 根据用例集合推导业务概念模型
    2. 根据用例中的动词和量词推导业务概念模型的关联关系
    3. 在特定的边界内根据模型的职责归纳子域

    重要!重要!重要!这里业务概念模型如果没有分析正确,那么下面要搞清楚是不容易的,这个分析部分是软件逻辑架构设计的基础。

    这个环节需要我们理解业务,更需要我们掌握问题空间建模这一严谨的方法论,这样我们才能推导出合理的模型,整个过程是非常严谨的,非常符合逻辑的。

    我在各 BU 分享现场做的多次实战演练之所以能成功的快速帮助同学们梳理出前面花一两个月都没有理出的模型,完全是因为于现场的同学对业务的理解(因为讨论之前我完全没有了解过对方的业务)和这套方法论(隐含在我的提问方式中)。所以说对业务的理解和方法论,两者缺一不可。

    3.2.2 对业务概念模型进行归纳

    在模型产出之后,我们要对模型进行归纳。

    什么叫归纳?

    归纳的意思是将所有的结果和想法合并,变成一种思维概念。或者让某个模型归属于某个已经存在的思维概念。且这些模型或者模块的职责不能超越这个高层次思维概念的边界。

    为什么要归纳?

    其实是为了保证相近的职责模型聚拢在一起从而保证职责的高内聚,同时明确出来的两个子域的边界,保证模块和模块之间的低耦合。

    对业务概念模型的归纳有助于做业务需求分析时判断高内聚和低耦合,而且在系统模型上,对系统模型进行分类也有助于做应用逻辑架构中模块的高内聚和低耦合,但是应用逻辑架构的不止高内聚和低耦合,还有其他让职责单一的方法,这些后面的章节会做介绍。

    3.2.3 按职责来进行归纳

    接下来我们来讲讲业务概念模型到业务概念架构判断方法:

    1)通过名词定义来进行归纳思维概念

    如果多个模型都在围绕某个名词,那么我们倾向将这个名词提炼出来。产品在设计时,基本上我们已经能够得一个粗略的业务模块划分,但是这个粗略的划分是不一定是合理:

    • 一是有可能我们的理解是不到位的,导致用错了名词,这个我们前面的文章中也提到过了。
    • 二是这个结果也只是一个粗略的结果,需要进一步精化。

    2)通过内聚的度量公式来进行归纳

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UsELldxe-1586353450971)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/2c349d0875c976aac23599339b43e4bd.jpg-wh_600x-s_3116303758-20200408104453565.jpg)]

    业务模型图中,模型和模型连线(连线就是模型和模型连接线)数量除以模型的梳理得到的值比较大的,那么我们可以看做是内聚,这些连线比较紧密我们趋向将其放到一个模块中,连线不是那么密切的,我们趋向于将它们放置在不同的模块中。然后我们再观察 连线数 / 模型数 观察内聚度量是高了还是低了,通过这样的方式归纳完成之后,我们再来通过度量公式来度量各模块的内聚和耦合程度。

    3)其他归纳方式

    如果我们划分出了基本模块,发现还有一些模型不确定应该放到哪些模块中,我们还可以使用创建者原则和信息专家原则来判断应该将该模型归纳如哪个模块。

    比如说,对存储系统进行系统建模,表和字段的关系在业务概念模型中是1对n的关系(在系统模型中是组合关系,强生命周期依赖,但是这里我们还没有到讨论应用逻辑架构的时候,只是在推导业务概念架构),此时将字段放到另外一个模块显然不合适,原因是根据创建者原则。

    当我们不清楚把字段模型放到哪个模块的时候,我们可以看看字段这个模型是由谁创建的。

    根据这条原则显然这里是表创建了字段,没有表对象,就没有字段对象,所以根据这条原则,我们就倾向于把字段模型放到表所在的模块中。

    重点:失去了最底层合理且正确的演绎,上层的归纳掌握的再好,也很难得出合理的结果。

    我们来看看归纳之后的效果示意图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9XSXdwL2-1586353450972)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/03994da00812517e02b3fad951d5a9a2.jpg-wh_600x-s_2001157331-20200408104453571.jpg)]

    图中的 A1,A2,A3,A4 之类是示意图,表示 A 模块内部还存在子模块,当然我们其实是先推导出子模块,然后对子模块再次进行高级别归纳,形成父模块。

    父模块层级再进行归纳,就形成了祖父模块,或者再向上形成曾祖父模块等等。粒度越大的模块,一般都对应更大的组织,越存在跨团队沟通,所以划清边界的要求就越高。

    3.3 业务流程

    除了业务模型之外,业务流程也是我们需要总结并明确的地方,这个地方主要明确的就是边界和异常分支等等,尤其是异常分支非常重要,很多业务方案的设计中对异常分支的考量是不重复的,这需要工程师对业务方案提出挑战,以明确业务方案中的各种流程的异常分支。

    3.4 业务概念架构总结

    我们工作中常见的推导有两种方式,一种是自顶向下推导,一种是自底向上推导,显然,两种推导使用的方法是不一样的。细心的读者会发现,其实我们刚刚说的问题空间领域模型和边界分析这套方法就是自底向上的演绎和归纳方法。

    四、基础逻辑架构推导(软件设计阶段)

    前面我们讲到了业务分析阶段,也是问题空间建模和问题空间业务概念架构梳理,业务分析阶段和软件没有任何关系。但本文中它是软件设计的前置条件,没有 get 到点的同学,请务必再把前一章仔细阅读。

    接下来我们来讲讲软件设计阶段我们需要产出的应用逻辑架构。

    4.1 再谈逻辑架构特性

    文章开头讲到了逻辑架构的相关特点,我们回顾一下:

    • 应用逻辑架构的作用:我们把前面那个例子再搬过来:如果拿汽车举例,那就是发动机模块中包含了哪些子模块(活塞,曲轴,连杆,缸体,缸盖,等等)发动机模块和变速箱模块之间的关联关系是什么,和底盘的关联关系是什么,发动机,底盘,变速箱,电子系统在整辆汽车中的职责,关系,约束是什么。这些都是用来指导汽车研发的。而不是指导用户如何使用这辆汽车的。
    • 目的:所以系统模型和应用逻辑架构都是用在软件设计阶段,其目的是用来指导软件的研发。
    • 受众:逻辑架构的受众有哪些呢?一般是这些人:研发人员,各层级架构师,各层级技术管理者,总的来说他们都是架构的设计者和实现者。

    这里还是请大家务必要跟产品功能架构区分开来,它们的受众和目标是不一样的。

    4.2 基础逻辑架构的推导概要

    在文章开头的图中,我们讲到应用逻辑架构来源于系统模型,数据模型,业务概念架构,还有流程,如下图所示。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WfzXJpWT-1586353450973)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/d50874fdd6563939d265576eb6db64db.jpg-wh_600x-s_2877069922-20200408104453581.jpg)]

    接下来,我们分别从三个角度来阐述逻辑架构的生成:

    1. 业务概念架构
    2. 模型(系统模型和数据模型)
    3. 流程(系统调用流和数据流)

    看到很多同学画的图没有区分出调用流和数据流,经常造成误解,造成沟通效率下降,甚至不能够准确的说明问题。所以在画图的时候,一定要注意区分调用流和数据流。

    接下来就根据业务概念架构和系统模型及流程来推导一下应用架构(逻辑架构)。我们来看一下一个简单的逻辑架构构成的 gif 示意图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DYFiYEha-1586353450974)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/3e0dfe8dc6f31f23ba9e1b376a7515f5.png)]

    从这张图中,我们可以看出应用逻辑架构是如何一步步被构成的,整个过程存在以下关键点:

    1)在业务概念架构的基础上推演应用逻辑架构。

    2)根据流程和系统模型来完善应用逻辑架构。

    3)横向提炼模块的问题:要实现业务模块,需要什么非业务模块的支撑,比如监控,报警,配置等等,而这部分内容往往还是可复用的。在上述动画中,可以理解成移动到最右侧的部分,当然可以移动到左侧,只是动画中没有体现出来。

    4)纵向提炼模块问题:有类似职责的模块在技术实现上是否可以提炼成可复用内容,提炼的结果可能是:

    • 独立的服务复用,在上述动画中,可以理解成最下方。
    • 或者二方库复用,在上述动画中,可以理解成最左或者最右侧。

    5)还有一些模块是为了支撑性能或者稳定性的,并非是从业务概念模型提炼而来,如图中深蓝色的模块。

    最终,出现的逻辑架构是分层的和分片的逻辑架构,下面我们来一步步阐述这个过程。

    4.3 根据业务概念架构推演

    业务概念架构图产出之后,基本上,我们逻辑架构的初步模型就具备了。所以我们可以理解成,第一步就是把业务概念架构直接先搬到应用逻辑架构中来,此处就不用多阐述了。

    啰嗦两句:尤其是较为顶层的粗粒度业务架构,一个是自顶向下分解得来,一个是自底向上演绎和归纳得来。而自顶向下分解尤其考验人对业务的理解能力,如果对业务理解不透彻,那很难产出合理的粗粒度业务概念架构。

    4.4 根据系统流程进行推演模块

    当业务概念架构产出之后,逻辑架构的骨架初成,接下来就是在这个框架上去填充内容。第一步就是根据流程来进行模块划分。

    总结一下,这里的方法就是,先根据业务流程,分解出系统时序图,根据时序图开始对模块进行归纳,从而得到粒度更大的模块。

    这是粒度比较细的根据流程划分模块的案例,在粒度更大的流程,此方法同样适用,看大家是工作在何种粒度上。

    通过流程来进行推导是我们日常工作必不可少的一部分,尤其当很多场景的流程具有业务共同点时,那么可以考虑提炼出这些业务共同点,以提升研发的效率。

    4.5 非业务线系统根据流程推导模块案例

    除了对流程进行归纳之外,我们还可以对系统模型进行归纳。我们知道,业务概念模型一般可以直接转换为系统模型,但是系统模型并不只是业务领域相关的模型,比如查询模型是一个经常出现的,这在 OLTP 的场景十分常见,而在 OLAP 的场景简直就是顶梁柱。非常常见的就是 SQL parser 模块,下图是 spark 体系中 SQL SQL 的主要流程和对应的模型,根据这个模型我们基本上也可以梳理出模块:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gtep0FO4-1586353450974)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/924b341744c5ef1d5ae305b32e12eb3c.jpg)]

    根据这个流程,我们发现了什么?我们发现了 spark 中是这样分模块的(这里面的模块已经落地成 package 了):

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jioXVW8R-1586353450975)(img/从方法到思维:什么是应用逻辑架构的正确姿势? .assets/c8f2558545d7e0582168530bcd490a8f.jpg-wh_600x-s_3196445516-20200408104453581.jpg)]

    所以说按照业务流程转换成的系统流程来推导模块是非常重要的手段。

    除此之外需要还需要强调的是,流程和模块一样,也是有粒度的,相同粒度的流程节点放在一起才更加容易推导出合理的架构模块。至于什么叫相同粒度,请参考一下《金字塔原理》。

    流程的粒度很重要,粒度粒度粒度,请重视流程的粒度。

    4.6 根据性能 & 稳定性 & 成本等进行提炼模块

    前面讲的都是从业务的角度来阐述架构的推导,接下来我们从计算机科学与技术的角度来阐述一下这些非功能性模块的推导,这里拿性能来举个例子吧。

    数据分析的报表场景降低 RT 的方案

    在一些数据分析产品中,绩效监控及报表展示是一个非常重要的场景,这个场景下的数据量是比较大的,为了降低 RT,我们不得不通过 ETL 对数据进行预计算,将原有的大表清洗成聚合之后的小表,以加快查询的速度。这样做的缺点是每次进行报表的修改,就要进行相关的ETL逻辑,高时间和人力成本,高性能。

    为了把高时间和人力成本 & 高性能转换成低成本&高性能,我们需要把人工操作转换成自动操作,把 ETL 的过程去除。

    第一个选择是将一个大表的数据存储到另外一个支持大数据下高性能的查询引擎,这样就极大的减少了 ETL 的操作,但是这样就带来一个问题,就是大数据量下把数据从 ODPS 导入到某个 ROLAP 的查询引擎中是比较耗时的,而且每次查询需要进行在海量数据中进行大量的 scan,但实际上获取的数据量并不大。这样的查询的 RT 依然需要亚秒级。

    第二个选择是根据报表的定义,自动的将判断出用户需要查询什么结果,将查询结果提前计算出来,然后只把这些少量的预计算后的结果导入到 ROLAP 引擎中(具体请参考 apache 开源项目 Kylin)。然后在报表的场景下,查询的 RT 下降到了百毫秒级。

    显然我们要实现第二种方式,这个时候在业务功能没有增加的情况下,我们必须要增加一个模块,在我们的产品中,我们称之为 intelligent cube,因为我们这里引入了机器学习算法对 cube 的构建进行了预测,无需或者只需非常少量的人为参与。

    最后导致逻辑架构中有部分是来自业务概念架构推导而来,有部分是系统流程推导而来,有部分是因为性能 & 成本的需要产生的设计。

    注意:理论上来讲,逻辑架构上需要指出模块之间的依赖关系,只是如果这样,不是特别美观,所以就根据上下和左右的位置来大概描述模块之间的关系了。

    这两个案例基本可以说明,根据性能 & 成本 & 稳定性推导出来的模块也是逻辑架构组成的重要部分。

    但是这个还只是一个场景一个场景来解决 RT 问题,虽然 icube 自己内部是有个体系的,但是通过这样的方式来解决 RT 问题对于整个架构来说也是自底向上构建的一个环节。在下一篇文章中,我们将会阐述相同的案例,但是思路是自顶向下来构建性能领域的体系化架构。同样一个事情,用不同的思路来做,对总目标的帮助是不一样的,而且两个方法是互补的,谁都少不了。

    这样的模块是如何得来的呢?

    看上去我们都已经知道了系统中有不少类似的纯技术相关的模块,但是这些模块内部是如何设计出来的呢?

    一般来说有如下方法帮助我们做这些模块的内部设计:

    1)调查业界的开源技术类产品中是否有类似功能的,比如预计算在业界有 kylin,而星环等专业大数据公司也都有自己的 cube 预计算产品。

    2)查阅业界相关的论文,比如说在预计算领域就已经研究了几十年,计算机发展的不同阶段有不同的论文,网上一搜一大堆,不断研究,必对工作有帮助。

    3)多关注业界的牛人,看看他们在想什么,说什么,参加参加相关的会议。

    4)自己通过逻辑和数据结构 & 算法推导出来。

    如果每次都只通过自己的逻辑和自己已经掌握的知识来进行方案的推导是不够的,一个是我们的技能有时候和事情是不匹配的,但是我们往往不知道这样的事实的存在,所以此时一定要虚心学习,请教他人,扩展自己的知识边界,才能做出更好的方案和技术决策。

    4.7 应用逻辑架构推导小结

    根据上文所述,基本上应用逻辑架构的推导有 4 个子路径,他们分别是:

    1. 业务概念架构:业务概念架构来自于业务概念模型和业务流程
    2. 系统模型:来自于业务概念模型
    3. 系统流程:来自业务流程
    4. 非功能性的系统支撑:来自对性能,稳定性,成本的需要

    每个子路径中都存在相关的具体方法。

    如果真的要想学习东西,而且想学的更快更深入,就要关注自己如何集中注意力,要思考自己的思考方式,研究自己的研究方式。

    Blog: https://blog.yilon.top

    展开全文
  • 代码编写规范目的:能够在编码过程中实现规范化,以后的程序开发中养成良好的行为习惯。 代码编写规范使用范围:J2EE项目开发。 一、包命名规范:目的:包的命名规范应当体现出项目资源良好的划分 1.servlet类...

    代码编写规范目的:能够在编码过程中实现规范化,为以后的程序开发中养成良好的行为习惯。


    代码编写规范使用范围:J2EE项目开发。


    一、包命名规范:
    目的:包的命名规范应当体现出项目资源良好的划分

    1.servlet类所在包命名规范:公司名称.开发组名称.项目名称.web.servlet
    例如:net.linkcn.web.servlet


    2.自定义标签类所在包命名规范:公司名称.开发组名称.项目名称.web.tags
    例如:net.linkcn.web.tags


    3.过滤器类所在包命名规范:公司名称.开发组名称.项目名称.web.filter
    例如:net.linkcn.web.filter


    4.Action类所在包命名规范:公司名称.开发组名称.项目名称.web.struts.action
    例如:net.linkcn.web.struts.action


    5.ActionForm类所在包命名规范:公司名称.开发组名称.项目名称.web.struts.form
    例如:net.linkcn.web.struts.form


    6.Javabean所在包命名规范:公司名称.开发组名称.项目名称.web.struts.service.impl
    例如:net.linkcn.web.service.impl


    7.Javabean实现接口命名规范:公司名称.开发组名称.项目名称.web.service
    例如:net.linkcn.web.service


    8.DAO类所在包命名规范:公司名称.开发组名称.项目名称.dao.impl
    例如:net.linkcn.dao.impl


    9.DAO类所实现的接口在包中命名规范:公司名称.开发组名称.项目名称.dao
    例如:net.linkcn.dao


    10.POJO类与hbm文件所在包命名规范:公司名称.开发组名称.项目名称.dao.hbm
    例如:net.linkcn.dao.hbm


    11.全局公共类、接口类所在包命名规范:公司名称.开发组名称.项目名称.global
    例如:net.linkcn.global


    12.全局工具类所在包命名规范:公司名称.开发组名称.项目名称.util
    例如:net.linkcn.util

     


    二、类命名规范
    基本命名规范:

    1.类、接口命名
    命名规范:以大写字母开头,如果有多个单词,每个单词头字母大写
    例如:StudentInfo

     

    2.接口命名

    命名规范:以大写字母"I"开头,如果有多个单词,每个单词头字母大写
    例如:IStudentInfo

    3.接口实现类命名:
    命名规范:将实现的接口名称的首字母"I"去掉,以"Impl作为结尾",如果有多个单词,每个单词头字母大写。
    例如:StudentInfoImpl

    4.J2EE+SSH框架命名规范
    servlet类命名:
    命名规范:以Servlet单词结尾
    例如:LoginServlet

    5.POJO命名:
    使用hibernate自动生成的类即可

    6.DAO类命名:
    使用hibernate自动生成的类即可

    7.Action类命名:
    命名规范:Action的命名以POJO名称来制定,POJO名称Action
    例如:
    一个POJO名称为Diary,其对应的action为DiaryAction

    8.ActionForm类命名:
    命名规范:ActionForm的命名以POJO名称来制定,POJO名称Form
    例如:
    一个POJO名称为Diary,其对应的actioForm为DiaryForm

    9.业务逻辑接口命名:
    命名规范:业务逻辑接口的命名以POJO名称来制定,IPOJO名称Service
    例如:
    一个POJO名称为Diary,其对应的业务逻辑接口为IDiaryService

    10.业务逻辑实现类命名:
    命名规范:业务逻辑接口实现类的命名以POJO名称来制定
    例如:
    一个POJO名称为Diary,对应的业务逻辑接口实现类名为DiaryServiceImpl

    11.类变量命名:
    命名规范:变量名首字母必须小写,如果该变量名有多个单词组成,后面的单 词首字母大写,单词与单词之间不要使用"_"做连接,变量名访问控制必须为私有, 可以对其增加setter与getter方法。
    例如:
    private int studentAge;
    public int getStudentAge(){
    return studentAge;
    }
    public void setStudentAge(int studentAge) {
    this.studentAge=studentAge;
    }

    12.常量命名:
    命名规范:所有字母大写,如果有多个单词组成,单词与单词之间以” _“隔开。而 且该变量必须是公共、静态、final类型
    例如:public static final String USER_NAME=”userName“;

    13.方法命名
    命名规范:首字母必须小写,如果该变量名有多个单词组成,后面的单词首字母 大写,单词与单词之间不要使用"_"做连接。单词不要使用名词。
    例如:public int checkLogin(String name,String pwd){}

    14.注释规范:

    注释规范是整个开发规范中最为重要的组成部分,必须严格执行。

    15.类的注释:
    作用:注释整个类,简单概述该类作用。
    书写规范:类的注释必须写在该类的声明语法之前。

    在注释中要描述该类的基 本作用,作者,日期,版本,公司名称,版权声明。
    格式:

    16.类的声明语法

    例如:public class AdminDAO

    17.变量、常量注释:
    作用:简单描述该变量的意义。
    书写规范:变量注释必须写在变量定义之前,简单描述其代表的意义。
    格式:
    例如:
    public int age;

    18.方法注释:
    作用:对该方法功能简单描述,其参数、返回值意义的注解。
    书写规范:方法注释必须写在方法定义之前。该注释包括:方法其功能的简单 描述,方法的参数、返回值类型、返回值意义简单的描述。
    格式:
    例如:
    public booleaneditAdminPassword(int adminId,String oldPassword,
    String password) throws UserException,ServiceException;

    三、Jsp页面命名:
    命名规范:jsp页面名称要以小写字母开头,如果有多个单词组成,后面的单词以 大写字母开头。名称要体现出该页面的意义,最好能够与模块名称联系在一起。
    例如:
    login.jsp --登录页面
    register.jsp --注册页面
    message.jsp --客户留言页面

     

    四、J2EE项目工程文件夹组织规范:
    目的:规范学员web应用程序的资源组织形式,形成良好的文件组织习惯。文件的组织形式应当体现模块的划分。

    1.根据eclipse工具的特征,项目的目录结构为:


    src
    ----存放java文件 
    WebRoot
    |--images --存放web程序所需的公共图片
    |--css --存放web程序所需的公共样式表
    |--js --存放web程序所需的公共js文件
    |--commons --存放web程序所需的公共文件
    |--功能模块文件夹(存放与某个功能模块相关的资源)
    |--images --存放与该功能模块相关的图片
    |--css --存放与该模块相关的样式表文件
    |--js --存放与该模块相关的js文件
    |--jsp、html页面
    |--WEB-INF
    |--classes
    |--lib
    |--tld文件

    2.J2EE项目提交规范

          项目完成时要将项目作为一个产品交付用户,良好的项目组织规范可以使用户可以方便的找寻项目中需要的资源,同时也是一个公司专业性的体现。项目提交时,要按照下列文件格式进行提交。

    1)项目主文件夹:
    作用:存放项目其他资源文件。

    命名规范:时间_班级编号_第X小组。
    例如:070706_GS2T18_第四小组。


    2)项目主文件夹下面包括以下文件夹和文件:
    |--src:保存.java文件。
    |--database:保存数据库的脚本文件或者数据库备份文件。
    |--source:保存eclipse工程中WebRoot目录下的所有文件。
    |--depend:保存编译该程序必须依赖的其他jar文件。
    |--javadoc:保存所有类生成的javadoc api文档。
    |--war:保存程序的归档文件
    |--xx.war:已经打包好的工程文件,可以直接运行。
    |--project:保存开发项目原工程代码及文件。
    |--产品说明书.doc:图文方式展现该产品使用方法。
    |--build.xml:ant脚本,用于生成运行的war文件。
    |--项目解说.ppt:进行项目讲解的ppt(ppt仅供在校模拟项目使用,不用于其他商业用途)
    注:一个完整的项目中,数据库必须有一定量的有效的测试数据来支持该程序的运行

    3)包的命名  
         Java包的名字都是由小写单词组成。但是由于Java面向对象编程的特性,每一名Java程序员都可以编写属于自己的Java包,为了保障每个 Java包命名的唯一性,在最新的Java编程规范中,要求程序员在自己定义的包的名称之前加上唯一的前缀。由于互联网上的域名称是不会重复的,所以程序 员一般采用自己在互联网上的域名称作为自己程序包的唯一前缀。 
    例如: net.frontfree.javagroup 

    4)类的命名 
        类的名字必须由大写字母开头而单词中的其他字母均为小写;如果类名称由多个单词组成,则每个单词的首字母均应为大写例如TestPage;如果类名 称中包含单词缩写,则这个所写词的每个字母均应大写,如:XMLExample,还有一点命名技巧就是由于类是设计用来代表对象的,所以在命名类时应尽量 选择名词。    
    例如: Circle 

    5)方法的命名 
        方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头。 
    例如: sendMessge 

    6)常量的命名 
    常量的名字应该都使用大写字母,并且指出该常量完整含义。如果一个常量名称由多个单词组成,则应该用下划线来分割这些单词。 
    例如: MAX_VALUE 

    7)参数的命名 
    参数的命名规范和方法的命名规范相同,而且为了避免阅读程序时造成迷惑,请在尽量保证参数名称为一个单词的情况下使参数的命名尽可能明确。 

    8)Javadoc注释 
        Java除了可以采用我们常见的注释方式之外,Java语言规范还定义了一种特殊的注释,也就是我们所说的Javadoc注释,它是用来记录我们代 码中的API的。Javadoc注释是一种多行注释,以结束,注释可以包含一些HTML标记符和专门的关键词。使用Javadoc 注释的好处是编写的注释可以被自动转为在线文档,省去了单独编写程序文档的麻烦。 
    例如: 

        在每个程序的最开始部分,一般都用Javadoc注释对程序的总体描述以及版权信息,之后在主程序中可以为每个类、接口、方法、字段添加 Javadoc注释,每个注释的开头部分先用一句话概括该类、接口、方法、字段所完成的功能,这句话应单独占据一行以突出其概括作用,在这句话后面可以跟 随更加详细的描述段落。在描述性段落之后还可以跟随一些以Javadoc注释标签开头的特殊段落,例如上面例子中的@auther和@version,这 些段落将在生成文档中以特定方式显示。

    9)变量和常量命名
         变量命名的方法采用匈牙利命名法,基本结构为scope_typeVariableName,它使用3字符前缀来表示数据类型,3个字符的前缀必须 小写,前缀后面是由表意性强的一个单词或多个单词组成的名字,而且每个单词的首写字母大写,其它字母小写,这样保证了对变量名能够进行正确的断句。

         例如, 定义一个整形变量,用来记录文档数量:intDocCount,其中int表明数据类型,后面为表意的英文名,每个单词首字母大写。这样,在一个变量名就 可以反映出变量类型和变量所 存储的值的意义两方面内容,这使得代码语句可读性强、更加容易理解。byte、int、char、long、float、 double、boolean和short。

        变量类型和首字母对照关系如下表:
    数据类型/对象类型 / 变量前缀 / 备注 
    byte bye 
    char chr 
    float flt 
    boolean bln 做布尔变量时,使用bln 
    Integer/int int 
    String str 
    Single sng 
    short sht 
    Long/long lng 
    Double/double dbl 
    Currency cur 
    Variant bln astr obj vnt 做布尔变量用时,用bln,做字符串数组用时,用astr,做为对象使用时,用obj,不确定时,用vnt。
    对于数组,在数据类型的前缀前再增加一个a,例如字符串数组为astr。对于在多个函数内都要使用的全局变量,在前面再增加“g_”。例如一个全局的字符串变量:g_strUserInfo。

    10)在变量命名时要注意以下几点:
    · 选择有意义的名字,注意每个单词首字母要大写。

    · 在一段函数中不使用同一个变量表示前后意义不同的两个数值。

    · i、j、k等只作为小型循环的循环索引变量。 

    · 避免用Flag来命名状态变量。 

    · 用Is来命名逻辑变量,如:blnFileIsFound。通过这种给布尔变量肯定形式的命名方式,使得其它开发人员能够更为清楚
    的理解布尔变量所代表的意义。 

    · 如果需要的话,在变量最后附加计算限定词,如:curSalesSum。 

    · 命名不相包含,curSales和curSalesSum。

    · Static Final 变量的名字应该都大写,并且指出完整含义。 

    · 如果需要对变量名进行缩写时,一定要注意整个代码中缩写规则的一致性。例如,如果在代码的某些区域中使用intCnt,而在另一些区域中又使用intCount,就会给代码增加不必要的复杂性。建议变量名中尽量不要出现缩写。 

    · 通过在结尾处放置一个量词,就可创建更加统一的变量,它们更容易理解,也更容易搜索。例如,请使用 strCustomerFirst和strCustomerLast,而不要使用strFirstCustomer和strLastCustomer。常 用的量词后缀有:First(一组变量中的第一个)、Last(一组变量中的最后一个)、Next(一组变量中的下一个变量)、Prev(一组变量中的上 一个)、Cur(一组变量中的当前变量)。

    · 为每个变量选择最佳的数据类型,这样即能减少对内存的需求量,加快代码的执行速度,又会降低出错的可能性。用于变量的数据类型可能会影响该变量进行计算所产生的结果。在这种情况下,编译器不会产生运行期错误,它只是迫使该值符合数据类型的要求。这类问题极难查找。

    · 尽量缩小变量的作用域。如果变量的作用域大于它应有的范围,变量可继续存在,并且在不再需要该变量后的很长时间内仍然占用资源。它们的主要问题是,任何类 中的任何方法都能对它们进行修改,并且很难跟踪究竟是何处进行修改的。占用资源是作用域涉及的一个重要问题。对变量来说,尽量缩小作用域将会对应用程序的 可靠性产生巨大的影响。 
    关于常量的命名方法,在JAVA代码中,无论什么时候,均提倡应用常量取代数字、固定字符串。也就是说,程序中除0,1以外,尽量不应该出现其他数 字。常量可以集中在程序开始部分定义或者更宽的作用域内,名字应该都使用大写字母,并且指出该常量完整含义。如果一个常量名称由多个单词组成,则应该用下 划线“_”来分割这些单词如:NUM_DAYS_IN_WEEK、MAX_VALUE。

    展开全文
  • C语言

    万次阅读 多人点赞 2019-12-18 23:01:50
    32.&&逻辑与 前后条件同时满足表达式真。 33.再用||的地方一般可以用|代替,但是用|的地方不能用||代替。 34.“&”取地址运算 35“”指针运算符 36.p是指针变量,则&p是变量p的地址 37.p是指针变量,则p是变量p所...

    公共考点
    1.算法的空间复杂度是指算法在执行过程中所需要的内存空间。
    2.算法的时间复杂度是指算法所需要的计算工作量。
    3.数据的逻辑结构与储存结构不是一一对应的。
    4.队列的修改是以先进先出的原则进行的。–与队列结构有关联的是先到先服务的作业调度。
    5.循环队列中的元素个数随队头指针和队尾指针变化而动态变化。
    6.C语言中的result只是一个自己定义的量
    7.对空和队满时,头尾指针均相等。
    8.冒泡法是在扫描过程中逐次比较相邻两个元素的大小。例:9+8+7+6+5+4+3+2+1=45.
    9.对象间的信息传递靠消息。
    10.多态性是指同一个操作可以是不同对象的行为。操作—对象。

    C语言
    1.源程序的扩展名为.c,目标程序的扩展名为.obj,可执行程序的扩展名为.exe(每个后缀为.c的C语言都可以单独进行编译)(C语言编译程序把.c编译成.obj的二进制文件)(链接形成.exe文件)
    2.循环结构、选择结构,顺序结构都是结构化程序的基本结构。
    3.N-S流程图是复杂算法的描述手段。
    4.长方形为处理框。椭圆形为连接点。
    5.一个c语言只能有一个主函数。
    6.函数的定义不可以嵌套,函数的调用可以嵌套。
    7.C语言总是以main函数开始执行。
    8.常量的类型:整型常量、实型常量、字符常量、字符串常量、符号常量。
    9.十进制整型常量:基本数字范围:0-9;(十进制小数两边必须有数字)
    八进制整型常量:以0开头,输出格式控制符为%o,基本数字范围0-7;
    十六进制整型常量:以0x开头,输出格式为%x,基本数字范围为0-15写为A-F或a-f;
    指数形式:e前必须有数字,e后必须为整数。
    10. 关键字属于标识符。(关键字不能做变量名也不能做函数名)
    11.数值型常量有整型常量、实型常量但均有正负值之分。
    12.语言的预编译处理可以可以用符号名代表一个常量定义是不必指定常量类型。
    13.实型常量又称实数或浮点数。在C语言中可以用单精度型和双精度型两种形式表示实型常量,分别用类型名float和double进行定义。实型常量在一般的微型集中占用4个字节,一般形式或者指数形式,数值范围都是-1038~1038,有效数字是7位。(不能是整形数据,如0)(常量的类型可以从字面上区分)(1为整型常量)(1.0为实型常量)(a为字符型常量)
    14.\0为八进制数,所以\09是错误的。
    15.字符常量在内存中占1个字节,字符常量可以进行关系运算。不能参与数值运算,可以参与任何整数运算。
    16.不能用字符串常量对字符数组名进行整体赋值操作。
    17.可以使用字符串常量来给一维数组进行复制。
    18.关于字节大小的问题

    16位编译器:char 1个字节  char* 2个字节 int 2个字节 float 4个字节 double 8个字节
    32位编译器:char 1个字节  char* 2个字节 int 4个字节 float 4个字节 double 8个字节
    64位编译器:char 1个字节  char* 2个字节 int 4个字节 float 4个字节 double 8个字节
    

    19.10进制转8进制,手算用 除8取余数法得
    20.十进制转十六进制为:除十六取余直到商为0,余数从后往前读。
    21.%f代表单精度浮点型数据(float),%lf代表双精度浮点型数(double)。
    单精度浮点数有效数字保证6位,部分7位,双精度浮点数有效数字保证15位,部分16位。
    22.sizeof可以看成是一个无符号整型表达式(sizeof为字节运算符)
    23.强制运算符:(类型名)(表达式) 逗号运算符:, 条件运算符::? :
    24. 赋值运算符左边必须是(一个)变量。
    25.a=bc,先运算bc,这个表达式的含义是,若b与c相等,那么得出的值为1,若不等则为0.
    26.“^” 按位异或 两数的二进制对应位相同,则为0,不同则为1.
    27.“|” 按位或 两个二进制中只要有一个为1,则结果为1。
    28.“~” 按位取反 二进制 0变1,1变0.
    29. “&”按位与 两个二进制都为1,则该位的结果为1,否则为零
    【 零的按位取反是 -1(0在数学界既不是正数也不是负数)
    所有正整数的按位取反是其本身+1的负数
    所有负整数的按位取反是其本身+1的绝对值 】
    30.位运算的对象只能是整形或字符型数据
    31.||逻辑或 前后条件只要有一个满足则为真。
    32.&&逻辑与 前后条件同时满足表达式为真。
    33.再用||的地方一般可以用|代替,但是用|的地方不能用||代替。
    34.“&”取地址运算
    35“”指针运算符
    36.p是指针变量,则&p是变量p的地址
    37.p是指针变量,则
    p是变量p所指向地址的值
    38.基类型不同的指针变量不可以相互混用
    39.函数的类型可以是指针类型
    40.函数的参数可以是整型、实型、字符型、指针类型。
    41.在这里插入图片描述

    42.C语言是一种计算机高级语言。
    43.C语言允许直接访问物理地址,能进行位操作。
    44.C语言是结构化程序设计语言
    45.c程序要通过编译,连接才能得到可执行的目标程序
    46.用c语言编写程序,可以编写出任何类型的程序
    47.C语言允许有空函数
    48.C程序书写格式,允许一行内可以写几个语句
    49.C程序的语句无行号(C语言中给源程序加行号;行号是用来定位代码的,指文件在几行)
    50.C语言的每个语句的最后必须有一个分号
    51.C语言本身没有输入输出语句(没有特定的输入输出语句)
    52.C语言可用来编写应用软件,也可用来编写系软件
    53.TurboC是在微机上广泛使用的编译程序
    54.C语言的数据结构是以数据类型形式出现的(不是常量和变量)
    55.空类型是C语言的一种数据类型
    56.C语言中数据有常量和变量之分
    57.利用指针和结构体类型可以构成表、树等复杂的数据结构
    58.在C程序中对所用到的所有数据都必须指定其数据类型
    59.c程序运行过程中,其值不能被改变的量称为常量
    60.在程序运行过程中,其值可以改变的量称为变量
    61.C语言可以用一个标识符代表一个常量,称为符号常量
    62.C语言规定标识符只能由字母、数字和下划线三种字符组成
    63.C语言整型常量可用十进制整数、八进整数和十六进制整数三种形式表示
    64.在现微机上使用的C编译系统,每一个整型变量在内存中占2个字节
    65.整型变量的基本类型符为int
    66.在微机上,一个长整型变量在内存中占4个字节(float型变量在内存中占4个字节)
    67.一个int型变量的最大允许值为32767
    68.在一个整常量后面加一个字母“L”或“1”.则认为该常量是longint 型常量
    69.C语言实型常量可用二进制小数和指数二种形式表示
    70.C语言实型变量分为:float型、double型、long double型三类
    71.C语言doule型一个变量的数值有效数字是16位
    72.C语言的字符常量是用单引号括起来的一个字符
    73.C语言的转义字符是以一个“\”开头的一种特殊形式的字符常量
    74.C语言中换行符使用’\n’,这是一个转义字符
    75.转文字符\r的含义是回车。
    76.C语言的字符型变量只能存放一个字符
    77.C语言允许字符数据与整数直接进行算术运算
    78.C语言允许在定义变量的同时使变量初始化
    79.C语言允许整型、实型、字符型数据间可以混合运算
    80.C语言规定两个整数相除的结果为整数
    81.用求余运算符“%”作运算,运算符两侧均应为整型数据
    82.用算术运算符和括号将运算对象按C语法规则组成的式子,称为C算术表达式
    83.算术运算符的结合方向为“自左至右”
    84.强制类型转换时,原来变量的类型未发生变化
    85.自增、自减运算符的结合方向为“自右至左”
    86.自增运算符只能用于变量,不能用于常量或表达式
    87指针.自增(减)运算符也可以用于指针变量,使指向下一个地址
    88.运算符“=”的作用是将一个数据赋给一个变量
    89.运算符“”的作用是将两侧数据是否相等
    90.赋运算符的结合方向是“自右向左”
    91.凡是二目运算符,都可以与赋值运算符一起组合成复合赋值运算符
    92.运算符“
    ”的作用是将一个数据赋给一个变量
    93.C语言不允许将实型数据赋给整型变量
    94.一个逗号表达式又可以与另一个表达式组成一个新的逗号表达式
    95.一个C程序可以由若干个源程序文件组成
    96.一个源文件可以由若千个函数和预处理命令以及全局变量声明部分组成
    97.空语句是C语言的一种语句
    98.复合语句中最后一个语句中最后的分号不能省略不写
    99.putchar函数的作用是向终端输出一个字符
    100.getchar函数的作用是从终端输入一个字符
    101.格式输出函数(print)一次可以输出多个数据
    102.printf函数的%ld格式参数,用来输入出长整型数据
    103.printf函数的%o格式参数,用来以8进制数形式输出整数
    104.printf函数的%f格式参数,用来以小数形式输出实数
    105.printf函数的%x格式参数,可以输出指定参数的16进制形式
    106.printf函数的%s格式参数,用来输出一个字符串
    107.C语言不是面向对象的程序设计语言
    108.printf函数的%e格式参数,以指数形式输出实数
    109.C语言单精度数的有效数一般为7位
    110.printf函数的%g格式参数
    111.%g是C语言printf()函数的一个输出格式类型,它表示以%f%e中较短的输出宽度输出单、双精度实数,在指数小于-4或者大于等于精度时使用%e格式
    112.p++是指下一个地址。
    (p)++是指将p所指的数据的值加一。
    C编译器认为
    和++是同优先级操作符,且都是从右至左结合的,所以p++中的++只作用在p上,和(p++)意思一样;在(p)++中,由于()的优先级比和++都高,所以++作用在()内的表达式*p上。比如有:
    int x,y,a[]={1,2,3,4,5},*p=a,*q=a;
    x=*p++;//执行这一句后x=a[0]=1,p=a+1
    y=(*q)++;//执行这一句后,y=a[0]+1=2,q仍然=a
    113. printf函数的附加格式说明字符“m”的含义是指输出数据的最小宽度
    114.scanf函数中的“格式控制”后面应当是变量地址(不是变量符)
    115.逻辑运算符>算术运算符>关系运算符>条件运算符>赋值运算符(罗算管调幅)
    116.条件运算符的结合方向是“自右向左"
    117.if语中又包含文可以转在电百度网点电 平句的嵌套
    118.条件运算符要求有3个操作对象,称为三目运算符
    119.条件表达式中三个表达式的类型可以不同
    120.switch语句是多分支选择语句
    121.switch语句中每一个case的常量表达式的值必须互不相同
    122.switch语句执行完一个case后面的语句后,流程控制转移到下一个case继续执行
    123.switch语句中多个case可以共用组执行语句
    124.goto语句为无条件转向语句
    125.C语句的循环语句中循环体如果包含一个以上的语句,必须以复合语句形式出现bre
    126.for循环语句中的3个表达式都可以省略
    127.C语句的一个循环体内允许又包含另一个完整的循环结构
    128.break语句不能用于循环语句和switch语句之外的任何其它语句中
    129.continue语句的作用是结束本次循环(而不是终止整个循环)
    130.C数组中的每一个元素都必须属于同一个数据类型
    131.C数组必须先定义,然后使用
    132.C语言规定只能逐个引用数组元素而不能一次引用整个数组
    133.在定义一维数组时可以只给一部分元素赋初值
    134.对二维数组初始化,可以分行给数组赋初值
    135.可以对二维数组的部分元素赋初值
    136.字符数组中的一个元素只存放一个字符
    137.如果一个字符数组中包含一个以上结束符’\0”,则遇第一个’\0’时输出就结束
    138.puts函数的作用是将一个字符串输出终端
    139.gets丽数的作用是从终端输入一个字符串到字符数组
    140.strlen 函数是测试字符串长度的函数
    141
    strcat函数是“字符串复制函数”。X
    strcpy函数是“字符串连接函数”。X
    strcmp函数是“字符串复制函数”。X
    strlwr函数是测试字符串长度的函数。X
    strupr函数是测试字符串长度的函数。X
    142.C程序一个函数可以被一个或多个函数调用多次
    143.一个C程序可由一个主函数和若干个其它函数构成
    144.C程序以源程序为单位进行编译(而不是函数)
    145.C程序由一个或多个源程序文件组成
    146.C语言在定义函数时是互相独立的,不能嵌套定义
    147.在调用有参函数时,主调函数和被调用函数之间有数据传递关系
    148.在调用一个函数的过程中又出现直接或间接地调用该函数本身称为函数的递归调用
    149.在一个函数内部定义的变量是内部变量,称为局部变量
    150.在函数之外定义的变量称为外部变量,是全局变量
    151.从变量的作用域角度来分,可以分为全局变量和局部变量(而不是静态和动态变量)
    152.静态存储方式是指在程序运行期间分配固定的存储空间的方式
    153.存储方法分为两大类:静态存储类和动态存储类
    154.C语言允许将局部变量的值放在CPU中的寄存器中,这种变量称为“寄存器变量”
    155.局部静态变量不能定义为寄存器变量
    156.如果一个函数只能被本文件中其它函数所调用,称为内部函数
    157.C源程序中的预处理命令,它不是C语言本身的组成部分
    158.宏定义不是C语句,在行末不加分号
    159.宏定又是用宏名代替一个字符串,只作简单的置换,不作正确性检查
    160.在进行宏定义时,可以引用已定义的宏名
    161.宏替换不占程序运行时间,只占编译时间
    162.文件包含处理是指个源文件可以将另一个的全部内容含进来源文件包
    163.一个include命令只能指定一个被包含文件
    164.存放变量地址的变量是指针变量
    165.C语言中变量的指针就是变量的地址
    166.函数的参数也可以是指针变量
    167.指针变量可以指向变量,也可以指向数组和数组元素
    168.引用数组元素可以用下标法,也可以用指针法
    169.用指针变量可以指向一维数组,也可以指向多维数组,用指针变量也可以指向一个函数
    170.一个函数可以带回一个整型值、字符值或实型值,也可以带回指针型的数据
    171.指针数组中的每一个元素都相当于一个指针变量
    172.指针数组中的每一个元素都相当于一个整型变量
    173.指针变量可以有空值,即该指针变量不指向任何变量
    174.若两个指针指向同一个数组的元素。则两指针变量可以进行比较
    175.用户自己定义一个结构教型后们其中并无具体数据
    176.在程序中使用的可和百网时 定义结构体类型的变量
    177.结构体类型的成员也可以是一个结构体变量
    178.结构体成员名可以与程序中的变量名相同
    179.不能将一个结构体变量作为一个整体进行输入和输出
    180.对结构体变量的成员可以像普通变量一样进行各种运算
    181.可以引用结构体变量的地址
    182.可以引用结构体变量成员的地址
    183.结构体数组的每个元素都是一个个结构体类型的数据
    184.对结构体数组可以初始化,即赋初值
    185.可以定义一个指针变量,用来指向一个结构体变量
    186.指针可以用结构体变量作链表中的结点
    187.malloc函数的返回值是一个指向分配域起始地址的指针
    188.建立动态链表是指在程序执行过程中从无到有地建立起一个链表
    189.使几个不同的变量共占同一段内存的结构,称为共用体类型的结构
    190.共用体变量所占的内存长度等于最长的成员长度
    191.定义了共用体变量,只能引用共用体变量中的成员(不能引用公用体变量)
    192.共用体变量的地址和它的各成员的地址都是同一地址
    193.共用体类型可以出现在结构体类型定义中
    194.结构体类型可以出在共用体类型定义中
    195.在C编译中,对枚举元素按常量处理
    196.一个整数不能直接赋给一个枚举变量
    枚举类型在C#或C++,java,VB等一些计算机编程语言中是一种基本数据类型而不是构造数据类型,而在C语言等计算机编程语言中是一种构造数据类型 。它用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。
    枚举可以根据Integer、Long、Short或Byte中的任意一种数据类型来创建一种新型变量。这种变量能设置为已经定义的一组之中的一个,有效地防止用户提供无效值。该变量可使代码更加清晰,因为它可以描述特定的值。
    197.可以用typedef声明新的类型名来代替已有的类型名
    198.位运算的运算量只能是整型或字符型的数据
    200.位运算符与赋值运算符可以组成复合赋值运算符
    在 C 语言中, 一种方法是用叫做位段的构造类型来定义一个压缩信息的结构。
    201.已有定义int (*p)( );指针p可以指向函数的入口地址
    202.C语言中运算对象必须是整型的是%=
    203.int *p 表达的是p是指向int型数据的指针。
    204函数rewind的功能是将文件指针重新指向一个流的开头(即使文件指针重新返回文件的开始位置),int rewind(FILE *stream);并且无返值。
    205.如果函数值的类型与返回值类型不一致,以函数值类型为准
    206.c语言中形参和实参类型不一致时以形参的类型为准
    207.形参应该是函数声明的时候就已经定义好
    208.若有定义int t[3][2],能正确表达t数组元素地址的是–t[2]+1
    209.int[]={1,2};
    210.C语言中的循环语句有for,while,do-while和goto,,***不是if、switch、break
    211.不正确的赋值语句是—ch‘a+b’,正确的是ch=‘\0’ ch=‘7’+‘9’ ch=7+9
    212.正确的赋值语句x3=12;
    213.C语言逻辑运算时,0为假,非0为真
    214.字符串常量是以双引号扩起来的字符序列“a”(其他C语言常量‘\n’ 012)(e-2不是C语言常量----实数的指数形式中,e后面必须有一个整数)

    301.一个位段必须存储在同一存储单元中
    302.位段的长度不能大于存储单元的长度
    303.一个c程序由若干个函数构成,其中有且仅有一个主函数
    304.指针变量中存放的是它所指对象的地址
    305.在C语言中,分号是语句的必然组成部分
    306.结构体变量所占空间是各成员所占空间之和
    307.数据文件可顺序读取,也可借助文件的定位操作实现随机读取
    308.从用户的角度上讲,类型的含义是规定了该类型变量的取值范围和运算范围
    309.c语言中,变量和函数均具有类型和存贮类别两个属性
    340.顺序结构>选择结构>循环结构
    341.函数返回值的类型是由函数定义时指定的类型
    342.*与s[]相等
    343.当从键盘输入数据时,对于整型变量可以输入整型数值和字符,对于实型变量可以输入实型数和整型数值等。
    344. getchar函数没有参数
    345.静态储存方式是在程序运行期间分配固定的储存方式的方式
    356.局部静态变量不能定义为寄存器变量
    357.不能把共用体变量作为函数的参数
    358.一个整数不能直接赋给一个枚举变量
    359.int *p=a 是对指针变量p的正确定义和初始化。
    360.Char s[]=”china”;
    Char p;
    P=s;
    p与s[]相等
    有int [],*p=a
    则p+5表示元素a[]的地址
    361.C语言中,退格符是\b
    362.C语言中,变量的隐含储存类别是auto
    363.实际参数和形式参数可以同名
    364.函数调用可以作为一个函数的形参
    365.结构化程序设计的3中结构是-顺序结构、选择结构、循环结构
    366.当从键盘输入数据时整型变量可以输出整型值和字符,对于实型变量可以输入实型数和整型数值
    367.C语言中逗号运算符的优先级最低,指针最优,单目运算优于双目运算。如正负号。
    先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7等价于 (1 << (3 + 2))&7.
    逻辑运算最后结合。
    368.C语言区分定义变量名的大小写
    369.设有如下定义:
    struck sk
    { int a;
    float b;
    } data;
    int *p;
    若要使P指向data中的a域,正确的赋值语句是(C)A、 p=&a; B、 p=data.a; C、 p=&data.a; D、 *p=data.a;
    370.double)a是将a转换成double类型;(int)(x+y)是将x+y的值转换成整型。
    371.设有以下说明语句:
    struct stu
    {
    int a;
    float b;
    }
    stutype;
    则下面叙述不正确的是( )。
    A) struct是结构体类型的关键字
    B) structstu是用户定义的结构体类型
    C) stutype是用户定义的结构体类型名
    D) a和b都是结构体成员名
    答案解析
    定义一个结构的一般形式为:
    struct结构体名
    {
    成员列表
    }变量名列表;
    本题中的stutype是在声明结构体类型structstu的同时定义的该结构体变量,而不是用户定义的结构体类型名。类型与变量是不同的概念; 2)对结构体中的成员,可以单独使用,它的作用与地位相当于普通变量;3)成员也可以是一个结构体变量; 4)成员名可以与程序中的变量名相同,二者不代表同一对象。
    372.C语言中的数据类型是指-函数返回值的数据类型
    373.C程序设计语言的基本成分是数据成分、运算成分、控制成分、传输成分。
    374.while(t=1)循环控制表达式的值为1。
    375.printf(++x);表示地址所连接的数值加1.
    376.int[3][4]; 表示a为3行
    4列的数组,它可用的最大行下标为2,列下标最大为3;
    若是引用a[0][4],则超过了数组的范围
    377.若有如下说明和定义
    struct test
    {
    int ml; char m2; float m3;
    union uu
    {
    char ul[5]; int u2[2];
    }
    ua;
    } myaa;
    则sizeof(struct test)
    的值是A.12 B.16 C.14 D.9
    正确答案:A
    在本题中,首先定义了一个结构体。在该结构体中,定义了一个整型变量成员、一个字符型变量成员和一个浮点型变量成员,并在结构体中定义了一个联合体变量成员,联合体变量成员中又包含两个联合体成员数组。题目最后要求计算该结构体变量所占的存储空间。
    在C语言中,联合体变量中的所有成员共享存储空间,联合变量的长度等于各成员中最长的长度,因此,本题的联合体部分所占的长度为5,但是结构体与联合体不一样的是,结构体不能共享空间,一个结构体变量的总长度是各成员长度之和,因此,该结构体所需的存储空间为5+1+2+4=12。本题的正确答案选A。
    378.静态储存类别的关键词是static
    379.C语言中提供了存储说明符auto,register,extern,static说明的四种存储类别。四种存储类别说明符有两种存储期:自动存储期和静态存储期。其中auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块是被建立,它在该程序块活动时存在,退出该程序块时撤销。
    380.fseek(文件指针,位移量,起始点)
    “起始点”用0,1或2代替,0代表“文件开始”,1为“当前位置”,2为“文件末尾”。“位移量”指以“起始点”为基点,向前移动的字节数。ANSIC和大多数C版本要求位移量是long型数据。这样当文件的长度大于 64k时不致出现问题。ANSI C标准规定在数字的末尾加一个字母L,就表示long型。
    381.若有定义:int (*p)[4];则标识符p ,是一个指针指向一个含有四个整形元素的一维数组。
    382.基本数据类型:整型、实型、字符型
    383.EOF是指向文本文件的结束标志,NULL是打开文件错误时的返回值。feof(fp)用来判断文件是否在文件末尾,文本文件和二进制文件均可以使用此函数,如果遇到文件结束就返回1,否则返回0。
    384.C语言的函数可以嵌套调用
    385.标准库函数fgets(s,n,f)的功能是什么–从文件f中读取长度不超过n-1的字符串存入指针s所指的内存。
    从流中读一行或指定个字符,
    原型是char *fgets(char *s, int n, FILE *stream);
    从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。
    形参注释:*string结果数据的首地址;n-1:一次读入数据块的长度,其默认值为1k,即1024;stream文件指针
    说得简单一点就是从f这个文件输入流中读取n-1个字符,存到s中。
    如果一行的字符数小于n-1,那么就是一行的字符数,所以应该理解为不超过n-1,如果一行的长度大于n-1,就是n-1个字符
    386.
    1、数据计算类型不同。基本数据类型分为三类:整数型(定点型)、实数型(浮点型)和字符型。除了基本数据类型,还有构造类型(数组、结构体、共用体、枚举类型)、指针类型、空类型void。
    2、各种数据类型的关键词不同。short、long、int、float、double、char六个关键词表示C语言里六种基本数据类型。
    3、不同数据类型占用内存的大小不同。short占2byte,int占4byte,long占4byte,float占2byte,double占8byte,char占1byte(不同的平台可能占用内存大小不一样,具体的可以用sizeof 测试下)。
    387.一个可以没有变量定义和执行部分,例如空函数

    展开全文
  • 目前,业界共有四种命名法则:驼峰命名法、匈牙利命名法、帕斯卡命名法和下划线命名法,其中前三种是较为流行的命名法。 驼峰命令法(Camel):  也称骆驼式命名法正如它的名称所表示的那样,是指混合使用大小写...

    三种流行的命名法则

    目前,业界共有四种命名法则:驼峰命名法、匈牙利命名法、帕斯卡命名法和下划线命名法,其中前三种是较为流行的命名法。

    驼峰命令法(Camel): 

    也称骆驼式命名法正如它的名称所表示的那样,是指混合使用大小写字母来构成变量和函数的名字例如,下面是分别用骆驼式命名法和下划线法命名的同一个函数:

    程序代码

    printEmployeePaychecks();
    print_employee_paychecks();

    第一个函数名使用了骆驼式命名法,函数名中的每一个逻辑断点都有一个大写字母来标记;第二个函数名使用了下划线法,函数名中的每一个逻辑断点都有一个下划线来标记 

    骆驼式命名法近年来越来越流行了,在许多新的函数库和Microsoft Windows这样的环境中,它使用得当相多另一方面,下划线法是c出现后开始流行起来的,在许多旧的程序和UNIX这样的环境中,它的使用非常普遍 

    驼峰式命名法分为大驼峰式命名规则:FirstName, CamelCase

    小驼峰式命名规则:firstName, camelCase

    [中间不需要空格 - _等分割符]

    匈牙利命名法(Hungarian): 

    广泛应用于象Microsoft Windows这样的环境中Windows 编程中用到的变量(还包括宏)的命名规则匈牙利命名法,这种命名技术是由一位能干的 Microsoft 程序员查尔斯- 西蒙尼(Charles Simonyi) 提出的

    匈牙利命名法通过在变量名前面加上相应的小写字母的符号标识作为前缀,标识出变量的作用域,类型等这些符号可以多个同时使用,顺序是先m_(成员变量), 再指针,再简单数据类型,再其它 

    例如:m_lpszStr, 表示指向一个以0字符结尾的字符串的长指针成员变量 

    匈牙利命名法关键是:标识符的名字以一个或者多个小写字母开头作为前缀;前缀之后的是首字母大写的一个单词或多个单词组合,该单词要指明变量的用途 

    匈牙利命名法的规则是:

    复制代码

    属性+类型+描述
    属性一般是小写字母+_:
    g_:全局变量
    m_:类成员变量
    s_:静态变量
    c_:常量
    类型就多了:
    b:bool
    sz:以零结束的字符串
    p:指针
    n:整整
    dw:双字
    l:长整型
    无符号:u
    函数:fn

    复制代码

    匈牙利命名法分为系统和应用两种。系统着眼于类型。应用着眼于语义,比如col表示行,c表示计数。

    帕斯卡(Pascal)命名法: 

    与骆驼命名法类似只不过骆驼命名法是首字母小写,而帕斯卡命名法是首字母大写,如:

    程序代码

    DisplayInfo(); 
    string UserName;

    pascal命名规则:大驼峰式命名规则

    三种命名规则的小结:

    MyData 就是一个帕斯卡命名的示例 
    而myData是一个骆驼命名法,它第一个单词的第一个字母小写,后面的单词首字母大写,看起来像一个骆驼 
    而iMyData是一个匈牙利命名法,它的小写的i说明了它的型态,后面的和帕斯卡命名相同,指示了该变量的用途.

    以上个人理解。总的来说,命名的最终目的是增加易读性,可读性。


    命名的基本原则

    (1)标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解——尽量采用采用英文单词或全部中文全拼表示,若出现英文单词和中文混合定义时,使用连字符“_”将英文与中文割开。较短的单词可通过去掉“元音”形成缩写;较长的单词可取单词的头几个字母形成缩写;一些单词有大家公认的缩写。例如:temp->tmp、flag->标志寄存器、statistic->stat、increment->inc、message->msg等缩写能够被大家基本认可。
    (2)命名中若使用特殊约定或缩写,则要有注释说明。应该在源文件的开始之处,对文件中所使用的缩写或约定,特别是特殊的缩写,进行必要的注释说明。
    (3)自己特有的命名风格,要自始至终保持一致,不可来回变化。个人的命名风格,在符合所在项目组或产品组的命名规则的前提下,才可使用。(即命名规则中没有规定到的地方才可有个人命名风格)。
    (4)对于变量命名,禁止取单个字符(如i 、j 、k... ),建议除了要有具体含义外,还能表明其变量类型、数据类型等,但i 、j 、k 作局部循环变量是允许的。变量,尤其是局部变量,如果用单个字符表示,很容易敲错(如i写成j),而编译时又检查不出来,有可能为了这个小小的错误而花费大量的查错时间。
    (5)除非必要,不要用数字或较奇怪的字符来定义标识符。
    (6)命名规范必须与所使用的系统风格保持一致,并在同一项目中统一。
    (7)在同一软件产品内,应规划好接口部分标识符(变量、结构、函数及常量)的命名,防止编译、链接时产生冲突。对接口部分的标识符应该有更严格限制,防止冲突。如可规定接口部分的变量与常量之前加上“模块”标识等。
    (8)用正确的反义词组命名具有互斥意义的变量或相**作的函数等。

    下面是一些在软件中常用的反义词组。

    复制代码

    add / remove begin / end create / destroy
    insert / delete first / last g et / release
    increment / decrement put / get
    add / delete lock / unlock open / close
    min / max old / new start / stop
    next / previous source / target show / hide
    send / receive source / destination
    cut / paste up / down
    示例:
    intmin_sum;
    intmax_sum;
    intadd_user( BYTE *user_name );
    intdelete_user( BYTE *user_name );

    复制代码

    (9)除了编译开关/ 头文件等特殊应用,应避免使用_EXAMPLE_TEST_ 之类以下划线开始和结尾的定义。


    变量名的命名规则

    (1)变量的命名规则要求用“匈牙利法则”。
    即开头字母用变量的类型,其余部分用变量的英文意思、英文的缩写、中文全拼或中文全拼的缩写,要求单词的第一个字母应大写。
    即: 变量名=变量类型+变量的英文意思(或英文缩写、中文全拼、中文全拼缩写)
    对非通用的变量,在定义时加入注释说明,变量定义尽量可能放在函数的开始处。
    见下表:

    复制代码

    bool 用b开头 b标志寄存器
    int 用i开头 iCount
    short int 用n开头 nStepCount
    long int 用l开头 lSum
    char用c开头 cCount
    unsigned char 用by开头
    float 用f开头 fAvg
    double 用d开头 dDeta
    unsigned int(WORD) 用w开头 wCount
    unsigned long int(DWORD) 用dw开头 dwBroad
    字符串 用s开头 sFileName
    用0结尾的字符串 用sz开头 szFileName

    复制代码

    (2)指针变量命名的基本原则为:

    对一重指针变量的基本原则为:“p”+变量类型前缀+命名,如一个float*型应该表示为pfStat。对二重指针变量的基本规则为:“pp”+变量类型前缀+命名。对三重指针变量的基本规则为:“ppp”+变量类型前缀+命名。
    (3)全局变量用g_开头,如一个全局的长型变量定义为g_lFailCount。即:变量名=g_+变量类型+变量的英文意思(或缩写)。此规则还可避免局部变量和全局变量同名而引起的问题。
    (4)静态变量用s_开头,如一个静态的指针变量定义为s_plPerv_Inst。即: 变量名=s_+变量类型+变量的英文意思(或缩写)
    (5)对枚举类型(enum)中的变量,要求用枚举变量或其缩写做前缀。并且要求用大写。如:

    复制代码

    enum cmEMDAYS
    {
    EMDAYS_MONDAY;
    EMDAYS_TUESDAY;
    ……
    };

    复制代码

    (6)对struct、union变量的命名要求定义的类型用大写。并要加上前缀,其内部变量的命名规则与变量命名规则一致。
    结构一般用S开头,如:

    struct ScmNPoint
    {
    int nX;//点的X位置
    int nY; //点的Y位置
    };

    联合体一般用U开头,如:

    union UcmLPoint
    {
    LONG lX;
    LONG lY;
    }

    (7)对常量(包括错误的编码)命名,要求常量名用大写,常量名用英文表达其意思。当需要由多个单词表示时,单词与单词之间必须采用连字符“_”连接。

    如:#define CM_FILE_NOT_FOUND CMMAKEHR(0X20B) 其中CM表示类别。

    (8)对const 的变量要求在变量的命名规则前加入c_。即:c_+变量命名规则;示例:const char* c_szFileName;

     

    函数的命名规范

    (1)函数的命名应该尽量用英文(或英文缩写、中文全拼、中文全拼缩写)表达出函数完成的功能——函数名应准确描述函数的功能。遵循动宾结构的命名法则,函数名中动词在前,并在命名前加入函数的前缀,函数名的长度不得少于8个字母。函数名首字大写,若包含有两个单词的每个单词首字母大写。如果是OOP 方法,可以只有动词(名词是对象本身)。示例:

    LONG GetDeviceCount(……);
    void print_record( unsigned int rec_ind ) ;
    intinput_record( void ) ;
    unsigned char get_current_color( void ) ;

    (2)避免使用无意义或含义不清的动词为函数命名。如使用process、handle等为函数命名,因为这些动词并没有说明要具体做什么。

    (3)必须使用函数原型声明。函数原型声明包括:引用外来函数及内部函数,外部引用必须在右侧注明函数来源: 模块名及文件名;内部函数,只要注释其定义文件名——和调用者在同一文件中(简单程序)时不需要注释。
    应确保每个函数声明中的参数的名称、类型和定义中的名称、类型一致。


    函数参数命名规范

    (1)参数名称的命名参照变量命名规范。
    (2)为了提高程序的运行效率,减少参数占用的堆栈,传递大结构的参数,一律采用指针或引用方式传递。
    (3)为了便于其他程序员识别某个指针参数是入口参数还是出口参数,同时便于编译器检查错误,应该在入口参数前加入const标志。

    如:……cmCopyString(const CHAR * c_szSource, CHAR * szDest)

    文件名(包括动态库、组件、控件、工程文件等)的命名规范文件名的命名要求表达出文件的内容,要求文件名的长度不得少于5个字母,严禁使用象file1,myfile之类的文件名。

    修改自参考链接

    http://xp9802.iteye.com/blog/2111721

    http://www.niubb.net/a/2015/04-23/281576.html

    展开全文
  • 文章目录驼峰命令法(Camel)匈牙利命名法(Hungarian)帕斯卡(Pascal)命名命名的基本原则变量名的命名规则函数的命名规范函数参数命名规范 三种流行的命名法则 目前,业界共有四种命名法则:驼峰命名法、匈牙利命名...
  • 所以本文中是笔者结合阿里巴巴开发规范,以及工作中的见闻针对 Java 领域相关命名进行整理和总结,仅供参考。 一,Java 中的命名规范 好的命名能体现出代码的特征,含义或者是用途,让阅读者可以根据名称的含义快速...
  • Java逻辑测试题

    千次阅读 2019-12-06 21:32:50
    一、选择题 针对以下题目,请选择最符合题目要求的答案。针对每一道题目,所有答案都选对,则该题得分,所选答案错误或不能选出所有答案,则该题不得分。... Java源文件经编译后,生成后缀class的字节码文件 ...
  • Python3中的命名规范大全---基于PEP8标准

    万次阅读 多人点赞 2018-08-28 11:05:41
    前言 Python 学习之旅,先来看看 Python 的代码规范,让...常量使用以下划线分隔的大写命名 MAX_OVERFLOW = 100 Class FooBar: def foo_bar (self, print_) : print(print_) 作者:两点水0 链接: ...
  • C语言命名规则

    千次阅读 2017-05-25 14:26:00
    C语言的一些命名规则,可适当参考
  • 文章目录一、三种流行的命名法则1、驼峰命令法(Camel):骆驼式命名法近年来越来越流行了,在许多新的函数库和Microsoft Windows这样的环境中,它使用得当相多另一方面,下划线法是c出现后开始流行起来的,在许多旧的...
  • #x负则相反,圆心在y轴负方向上,y正,顺时针画圆,圆弧角度y turtle. seth (to_angle)函数的作用是设置小海龟当前行进方向to_angle,to_angle是角度的整数值 turtle. fd (distance)函数的作用是向...
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    文件doc版,可自行转成txt,在手机上看挺好的。 本资源来自网络,如有纰漏还请告知,如觉得还不错,请留言告知后来人,谢谢!!!!! 入门学习Linux常用必会60个命令实例详解 Linux必学的60个命令 Linux提供...
  • 1.本章主要内容: 网络和网络协议 tcp/ip的历史 tcp/ip的重要特性 2.网络协议概述   3.tcp/ip协议 tcp/ip协议定义了网络通信的过程,更重要的是,定义了数据单元的格式和内容,以便接收计算机能够正确...
  • 【多选题】以下选项属于 Python 整数类型的是( )【其它】根据CAD原文件绘制别墅立面图:如图 别墅立面图002.dwg【单选题】字符串是一个连续的字符序列,用________方式打印出可以换行的字符串。【单选题】下列不合法的...
  • 数字电路信号逻辑电平标准详解

    万次阅读 2019-05-03 21:00:34
    最基本的单端信号逻辑电平CMOS、TTL,在此基础上随着电压摆幅的降低,出现LVCMOS、LVTTL等逻辑电平,随着信号速率的提升又出现ECL、PECL、LVPECL、LVDS、CML等差分信号逻辑电平。 而什么是逻辑电平呢,个人的...
  • 逻辑卷的创建及使用

    千次阅读 2019-08-14 20:18:35
    VM逻辑卷 综合分区: 图形添加一块100G硬盘,划分3个主分区,一个扩展分区,三个逻辑分区 [root@server0 ~]# lsblk [root@server0 ~]# fdisk /dev/vdc n 创建主分区—>回车—>回车---->回车---->在last...
  • 测试开发需要学习的知识结构

    万次阅读 多人点赞 2018-04-12 10:40:58
    努力成为一个优秀的测试开发从业者,加油!... - 假装在测试的回答 - 知乎白盒与黑盒测试什么区分1、黑盒测试 黑盒测试也称功能测试或数据驱动测试,它是在已知产品所应具有的功能,通过测试来检...
  • 编程规范(一):C/C++的命名原则

    千次阅读 2018-10-07 12:02:51
    符合规范的统一命名是程序编写的基本规矩之一。很多时候我们不愿意接手别人的代码,原因之一就是代码命名很乱;我们自己写代码时经常写到后面忘了前面,也有可能是我们没有养成规范的命名习惯。当写代码成为一种艺术...
  • 测试开发笔记

    万次阅读 多人点赞 2019-11-14 17:11:58
    不是必须做的, 必须做测试的 1公共的主要模块 2核心模块 3和外界软件接口模块 1被测的产品 2概要设计说明书 3集成测试工程师 4概要设计人员 单元测试 unit testing(UT) 函数 代码 逻辑 白盒测试 验证函数代码逻辑...
  • 笔者自己总结的非官方图片命名规则:图片类型_逻辑名称_功能名称{_颜色}{_大小}{_状态}
  • 程序开发的命名规范(必读)

    万次阅读 多人点赞 2016-09-28 16:24:55
    良好的命名规范可以团队合作开发推波助澜,无论在项目开发,还是产品维护上都起到了至关重要的作用。应该说命名规范是一种约定,也是程序员之间良好沟通的桥梁。另外古人相信只要知道一个人真正的名字就会获得凌驾...
  • 实验实例 —逻辑门设计

    千次阅读 2019-02-18 12:12:02
    实例一 逻辑门设计(基于Robei的实验案例) 2.1.1. 本章导读 数字逻辑是芯片电路的基本组成部分。本次设计主要分析数字逻辑门在Robei软件中利用Verilog语言实现的方式,并通过该设计让参与者快速体验并掌握“图形...
  • TensorFlow入门

    千次阅读 多人点赞 2019-04-23 10:09:29
    Name代表的是张量的名字,也是张量的唯一标识符,我们可以在每个op上添加name属性来对节点进行命名,Name的值表示的是该张量来自于第几个输出结果(编号从0开始),上例中的“mul_3:0”说明是第一个结果的输出。...
  • 1.数据库设计14规则 1. 原始单据与实体之间的关系   可以是一对一、一对多、多对多的关系。...这里的实体可以理解基本表。明确这种对应关系后,对我们设计录入界面大有好处。   〖例1〗:一份员工履
  • 命名规范 常量定义 代码格式

    千次阅读 2018-04-03 09:54:59
    从远程仓库拉取代码的类命名为  PullCodeFromRemoteRepository 。    反例: 变量  int a;  的随意命名方式。    12.  【推荐】如果模块、接口、类、方法使用了设计模式,在命名时体现出具体模式。    ...
  • 1. 按照"后进先出”原则组织数据的数据结构是____队列栈双向链表二叉树2. 以下选项的叙述中,正确的是循环队列有队头和队尾两个指针,因此,循环队列... 关于数据的逻辑结构,以下选项中描述正确的是存储在外存...
  • Web命名规范

    千次阅读 2018-04-12 16:20:56
    HTML编码规范(一)命名规则: 头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left right c...
  • 软件测试面试题汇总

    万次阅读 多人点赞 2018-09-27 12:31:09
    转载自: ... 软件测试面试题汇总 测试技术面试题 ...........................................................................................................
  • 0)Service/DAO层方法命名规约 1)获取单个对象的方法用get做前缀。 2)获取多个对象的方法用list做前缀。 3)获取统计值的方法用count做前缀。 4)插入的方法用save(推荐)或insert做前缀。 5)删除的方法用remove...
  • 【数据库学习】数据库总结

    万次阅读 多人点赞 2018-07-26 13:26:41
    1,数据库 1)概念 数据库是长期存储在计算机内、有组织的、可共享的大量数据的集合。 常见数据库管理系统有:Access、mysql、sql server 2)特点 ...逻辑数据独立性(logical data...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 102,365
精华内容 40,946
关键字:

以下产品的命名逻辑正确的为