面向对象的需求分析方法

面向对象的需求分析方法

  面向对象的需求分析方法的核心是利用面向对象的概念和方法为软件需求建造模型。它包含面向对象风格的图形语言机制和用于指导需求分析的面向对象方法学。

  面向对象的思想最初起源于 20世纪 60年代中期的仿真程序设计语言Simula67。20世纪80年代初出现的Smalltalk 语言及其程序设计环境对面向对象技术的推广应用起到了显著的促进作用。20世纪90年代中后期诞生并迅速成熟的UML(Unified Modeling Language,统一建模语言)是面向对象技术发展的一个重要里程碑。UML 统一了面向对象建模的基本概念、术语和表示方法,不仅为面向对象的软件开发过程提供了丰富的表达手段,而且也为软件开发人员提供了互相交流、分享经验的共用语言。

  本章首先介绍面向对象的主要概念和思想。在概述了UML的全貌之后,以“家庭保安系统”为实例,介绍与需求分析相关的部分 UML语言机制以及基于UML的面向对象的需求分析方法和过程。

第一节 面向对象的概念与思想

  一、面向对象的概念

  关于“面向对象”,有许多不同的看法。Coad和 Yourdon给出了一个定义:“面向对象 = 对象 + 类 + 继承 + 消息通信”。如果一个软件系统是使用这样4个概念设计和实现的,则认为这个软件系统是面向对象的。一个面向对象的程序的每一成分应是对象,计算是通过新的对象的建立和对象之间的消息通信来执行的。

  1.对象(object)

  一般意义来讲,对象是现实世界中存在的一个事物。可以是物理的,如一个家具或桌子 ,如图 5-1-1所示,可以是概念上的 ,如一个开发项目。对象是构成现实世界的一个独立的单位,具有自己的静态特征(用数据描述)和动态特征(行为或具有的功能)。例如:人的特征:姓名、性别、年龄等,行为:衣、食、住、行等。

 

图 5-1-1 对象的定义

  (1)对象、属性、操作、消息定义

  对象可以定义为系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位,由一组属性和一组对属性进行操作的服务组成。

  属性一般只能通过执行对象的操作来改变。

  操作又称为方法或服务,在C ++中称为成员函数,它描述了对象执行的功能,若通过消息传递,还可以为其他对象使用。

  而所谓的消息是一个对象与另一个对象的通信单元,是要求某个对象执行类中定义的某个操作的规格说明。发送给一个对象的消息定义了一个操作名和一个参数表(可能是空的),并指定某一个对象。由一个对象接收的消息则调用消息中指定的操作,并将传递过来的实际参数与参数表中相应的形式参数结合起来。接收对象对消息的处理可能会改变对象中的状态,即改变接收对象的属性,并发送一个消息给自己或另一个对象。可以认为,这种消息的传递大致等价于过程性范型中的函数调用。

  (2)对象的分类

  ·外部实体:与软件系统交换信息的外部设备、相关子系统、操作员或用户等。

  ·信息结构 :问题信息域中的概念实体 ,如信号、报表、显示信息等。

  ·需要记忆的事件:在系统运行过程中可能产生并需要系统记忆的事件,如单击鼠标左键、击打键盘“?”键等。

  ·角色:与软件系统交互的人员所扮演的角色,如经理、部长、技术支持等。

  ·组织机构:有关机构,如单位、小组等。

  ·位置:作为系统环境或问题上下文的场所、位置,如客户地址、收件人(机构)地址等。

  ·操作规程:如操作菜单、某种数据输入过程等。

  在标识对象时必需注意遵循“信息隐蔽”的原则:必需将对象的属性隐藏在对象的内部,使得从对象的外部看不到对象的信息是如何定义的,只能通过该对象界面上的操作来使用这些信息。对象的状态通过给对象赋予具体的属性值而得到。它只能通过该对象的操作来改变。

  对象有两个视图,分别表现在分析设计和实现方面。从分析及设计方面来看 ,对象表示了一种概念 ,它们把有关的现实世界的实体模型化。从实现方面来看,一个对象表示了在应用程序中出现的实体的实际数据结构。之所以有两个视图,是为了把说明与实现分离,对数据结构和相关操作的实现进行封装。

  2.类(class)和实例(instance)

  把具有相同特征和行为的对象归在一起就形成了类。类成为某些对象的模板,抽象地描述了属于该类的全部对象的属性和操作。属于某个类的对象叫做该类的实例。对象的状态则包含在它的实例变量,即实例的属性中。如图 5-1-2所示。从“李杰”、“王辉”和“杨芳”等对象可得到类“学生”,而这些对象就称为该类的实例。

 

图 5-1-2 对象、类与实例

  类定义了各个实例所共有的结构,类的每一个实例都可以使用类中定义的操作。实例的当前状态是由实例所执行的操作定义的。

  面向对象程序设计语言,如C++和 smalltalk都定义了一个new操作,可建立一个类的新实例。C++ 还引入了构造函数,用它在声明一个对象时建立实例。此外,程序设计语言给出了不同的方法,来撤消(称为析构)实例,即当某些对象不再使用时把它们删去,把存储释放以备其他对象使用。C++给出了一个操作delete,可以释放一个对象所用的空间。C++还允许每个类定义自己的析构方法,在撤消一个对象时调用它。smalltalk 没有提供一个机制来撤消对象,但可以进行无用单元收集。

  类常常可看做是一个抽象数据类型(ADT)的实现 。但更重要的是把类看做是表示某种概念的一个模型。事实上,类是单个的语义单元,它可以很自然地管理系统中的对象,匹配数据定义与操作。类加进了操作,给通常的记录赋予了语义,可提供各种级别的可访问性。

  3.继承 (inheritance)

  如果某几个类之间具有共性的东西(信息结构和行为),抽取出来放在一个一般类中,而将各个类的特有的东西放在特殊类中分别描述,则可建立起特殊类对一般类的继承,如图 5-1-3所示。各个特殊类可以从一般类中继承共性,这样避免了重复。

 

图 5-1-3 特殊类对一般类的继承关系

  建立继承结构的好处:

  ·易编程、易理解 代码短, 结构清晰;

  ·易修改:共同部分只要在一处修改即可;

  ·易增加新类:只须描述不同部分。

  4.多继承

  如果一个类需要用到多个既存类的特征,可以从多个类中继承,称为多继承。例如退休教师是继承退休者和教师这两个类的某些特征或行为而得到的一个新类。

 

图 5-1-4 多继承

  5.多态性和动态绑定

  对象互相通信,即一个对象发消息给另一个对象,执行某些行为或又发消息给另外的对象,从而执行系统的功能。

  发送消息的对象可能不知道另一个对象的类型是什么。如在 C程序中使用命令ClearInt () 时要严格区分该命令适合一个整数,还是一个整数数组。但在C++情形,ClearInt ()对两者都适用,它自己判断对象是哪一个。

  这就是多态性。它意味 着一个操作 在不同类中可以有不同的实现方式。如清零操作 ClearInt ( ) 针对消息对象是 int array 还是int,其实现是不同的。在一个面向对象的多态性语言中,可能代替一个特定类型的类型的集合就是它的子类集合。

  例如,图 5-1-5给出了 4个类的继承层次。使用这个继承结构,发送给多边形类的所有消息,它的所有子类都能够响应。又例如,想要在屏幕上画一系列多边形,多态性允许一个表的元素可以属于一组指定的类型而不仅仅是一个类型,可以认为这是一个类族。通过遍历这个表,发送给各个表元素以draw消息,画出所有的多边形。

 

图 5-1-5 4个类的继承层次

  动态绑定把函数调用与目标代码块的连接延迟到运行时进行。这样,只有发送消息时才与接收消息实例的一个操作绑定。它与多态性可以使我们建立的系统更灵活,易于扩充。做为动态绑定的例子,考虑在多边形类中的方法contains ? (aPoint) 。这个操作可以在类层次的各层重新实现,以有效利用各个子类的特殊的特征。例如,假定一个矩形有某些边与屏幕的边平行,这时,检查一个点是否包含在矩形内,比检查一个点是否在一个一般的四边形内的效率要高一些。

二、面向对象软件开发的分析模型

  面向对象分析过程分为论域分析和应用分析。论域分析建立大致的系统实现环境,应用分析则根据特定应用的需求进行论域分析。

  1.OOA分析的基本原则和任务

  为建立分析模型,要运用如下的5个基本原则 :①建立信息域模型;②描述功能;③表达行为;④划分功能 、数据 、行为模型,揭示更多的细节;⑤用早期的模型描述问题的实质,用后期的模型给出实现的细节。这些原则形成OOA的基础。

  OOA的目的是定义所有与待解决问题相关的类(包括类的操作和属性、类与类之间的关系以及它们表现出的行为)。为此,OOA需完成的任务是:

  (1)软件工程师和用户必须充分沟通,以了解基本的用户需求;

  (2)必须标识类(即定义其属性和操作);

  (3)必须定义类的层次;

  (4)应当表达对象与对象之间的关系(即对象的连接);

  (5)必须模型化对象的行为;

  (6)反复地做任务①~⑤,直到模型建成。

  2.OOA概述

  目前已经衍生许多种 OOA方法。每种方法都有各自的进行产品或系统分析的过程,有一组可描述过程演进的图形标识,以及能使得软件工程师以一致的方式建立模型的符号体系。现在广泛使用的OOA方法有以下几种:

  (1) Booch 方法:Booch 方法包含“ 微开发过程 ”和“宏开发过程”。微开发过程定义了一组任务,并在宏开发过程的每一步骤中反复使用它们,以维持演进途径。Booch OOA 宏开发过程的任务包括标识类和对象、标识类和对象的语义、定义类与对象间的关系,以及进行一系列求精从而实现分析模型。

  (2) Rumbaugh 方法:Rumbaugh 和他的同事提出的对象模型化技术(OMT)用于分析、系统设计和对象级设计 。分析活动建立三个模型:对象模型(描述对象、类、层次和关系),动态模型(描述对象和系统的行为),功能模型(类似于高层的DFD,描述穿越系统的信息流)。

  (3) Coad和Yourdon 方法:Coad和Yourdong方法常常被认为是最容易学习的OOA 方法。建模符号相当简单,而且开发分析模型的导引直接明了。其OOA过程概述如下:

  ·使用“要找什么”准则标识对象;

  ·定义对象之间的一般化∕特殊化结构;

  ·定义对象之间的整体∕部分结构;

  ·标识主题(系统构件的表示);

  ·定义属性及对象之间的实例连接;

  ·定义服务及对象之间的消息连接。

  (4) Jacobson方法:也称为OOSE(面向对象软件工程)。Jacobson方法与其他方法的不同之处在于他特别强调使用实例(use case)——用以描述用户与系统之间如何交互的场景。Jacobson方法概述如下:

  ·标识系统的用户和它们的整体责任;

  ·通过定义参与者及其职责、使用实例、对象和关系的初步视图,建立需求模型;

  ·通过标识界面对象、建立界面对象的结构视图、表示对象行为、分离出每个对象的子系统和模型,建立分析模型。

  (5) Wirfs―Brock 方法:Wirfs―Brock 方法不明确区分分析和设计任务 。从评估客户规格说明到设计完成 ,是一个连续的过程 。与Wirfs―Brock分析有关的任务概述如下:

  ·评估客户规格说明;

  ·使用语法分析从规格说明中提取候选类;

  ·将类分组以表示超类;

  ·定义每一个类的职责;

  ·将职责赋予每个类;

  ·标识类之间的关系;

  ·基于职责定义类之间的协作;

  ·建立类的层次表示;

  ·构造系统的协作图。

  (6) 统一的OOA方法(UML) 。统一的建模语言(UML)已经在企业中广泛使用,它把Booch、Rumbaugh和Jacobson 等各自独立的OOA和OOD方法中最优秀的特色组合成一个统一的方法。UML 允许软件工程师使用由一组语法的语义的实用的规则支配的符号来表示分析模型。

  在UML中用5种不同的视图来表示一个系统,这些视图从不同的侧面描述系统。每一个视图由一组图形来定义。这些视图概述如下:

  ·用户模型视图:这个视图从用户( 在UML中叫做参与者)角度来表示系统。它用使用实例(use case)来建立模型,并用它来描述来自终端用户方面的可用的场景。

  ·结构模型视图 :从系统内部来看 数据和功能性 。即对 静态结构(类、对象和关系)模型化。

  ·行为模型视图:这种视图表示了系统动态和行为。它还描述了在用户模型视图和结构模型视图中所描述的各种结构元素之间的交互和协作。

  ·实现模型视图:将系统的结构和行为表达成为易于转换为实现的方式。

  ·环境模型视图:表示系统实现环境的结构和行为。

  通常,UML 分析建模的注意力放在系统的用户模型和结构模型视图,而UML设计建模则定位在行为模型、实现模型和环境模型。

第二节 UML概述

  一、UML的语言机制

  在UML 诞生之前,面向对象领域已经涌现出了许多开发方法及相应的表示机制,它们各有千秋 ,却又有很多类似之处 ,往往让使用者无所适从。UML在这样的背景下应运而生。它主要以BOOCH 方法、OMT方法(71)和OOSE方法为基础,同时也吸收了其他面向对象建模方法的优点,形成一种概念清晰、表达能力丰富、适用范围广泛的面向对象的标准建模语言。

  UML 通过图形化的表示机制从多个侧面对系统的分析和设计模型进行刻画。它共定义了10种视图,并将其分为如下4类:

  (1)用例图(use case diagram) 。从外部用户的角度描述系统的功能,并指出功能的执行者。

  (2)静态图。包括类图(class diagram)、对象图(object diagram) 和包图(pack diagram)。类图描述系统的静态结构,类图的节点表示系统中的类及其属性和操作,类图的边表示类之间的联系,包括继承、关联、依赖、聚合等。对象图是类图一个实例,它描述在某种状态下或在某一时间段,系统中活跃的对象及其关系。在对象图,一个类可以拥有多个活跃的对象实例。包图描述系统的分解结构,它表示包(package)以及包之间的关系。包由子包及类组成。包之间的关系包括继承、构成与依赖关系。

  (3)行为图。包括交互图(interactive diagram)、状态图(statechar diagram) 与活动图(activity diagram),它们从不同的侧面刻画系统的动态行为。交互图描述描述对象之间的消息传递,它又可分为顺序图(sequence diagram)与 合作图(collaboration diagram)两种形式。顺序图强调对象之间消息发送的时间序。合作图更强调对象间的动态协作关系。合作图也可通过消息序号之间消息发送的时间序。只不过这种表示不如顺序图那样直观 。状态图描述类的对象的动态行为 ,它包含对象所有可能的状态、在每个状态下能够响应的事件以及事件发生时的状态迁移与响应动作。活动图描述系统为完成某项功能而执行的操作序例,这些操作序列可以并发和同步。活动图中包含控制和信息流。控制流表示一个操作完成后对其后操作的触发,信息流则刻画操作之间的信息交换。

  (4)实现图(implementatin diagram)。包括构件图(component diagram)与 部署图(deploymetn diagram),它们描述软件实现系统的组成和分布状况。构件图描述软件实现系统中各组成部件以及它们之间的信赖关系。一个部件可能是一个资源描述文件、一个二进制文件或一个可执行文件。构件图主要用于理解和分析软件各部分之间的相互影响程度。部署图描述作为软件系统运行环境的硬件及网络的物理体系结构,其节点表示实际的计算机和设备,边表示节点之间物理连接关系,也可显示连接的类型及节点之间的依赖性。在节点内部,可以放置可执行部件和对象以显示节点与可执行软件单元之间的对应关系。部署图对于软件安装工程师有着重要的参考价值。

  例如,图5-2-1表示某大学的课程注册管理系统包含3个用例:“课表维护”、“个人课程规划”和“选课学生花名册查询”。教务管理人员使用“课表维护”用例设置或修改课程属性(课程的时间、地点、上课老师等)和增删课程;学生使用“个人课程规划”用例选课和修改自己的个人课表,收费管理系统根据每个学生的选课情况计算其应缴费用;老师使用“选课学生花名册查询”用例获取选定其所开课程的学生花名册。



图 5-2-1 课程注册管理系统的用例图

  图 5-2-2表示前述的课程注册管理系统包含“教务管理人员”、“学生”、“老师”、“课程”、“课程设置”、“课程注册表”、“课程注册管理器”和“课程管理器”8个类。前3个类为一般化的“用户”类的子类。一门“课程”可由一到多个“课程设置”构成,例如,对于全校性的公共基础课,由于选修的学生太多,必须安排不同的老师、不同的教室和不同的时间段。“学生” 、“老师”与“课程设置”之间 ,“课程注册表”与“课程注册管理器”之间以及“课程注册管理器”与“课程”之间存在着关联关系。



图 5-2-2 课程注册管理系统的类图

  图5-2-3通过UML顺序图刻画了“个人课程规划”用例中学生选课功能的实现过程。



图 5-2-3 用UML顺序图表示“个人课程规划”用例中的学生选课过程

  图 5-2-4用UML协作图刻画学生选课过程,该图与图 5-2-3等价。



图 5-2-4 用UML协作图表示“个人课程规划”用例中的学生选课过程

  图 5-2-5“课程设置”对象的状态图。它表示每个“课程设置”最多只能容纳50个选课学生。



图 5-2-5 UML状态图示例

  本章的后继章节结合需求分析过程更具体地介绍UML的用例图、包图、类图和活动图,第八章将结合软件设计过程详细介绍顺序图、协作图、状态图和活动图。对其他UML 图形机制感兴趣的读者,以及希望进一步深入了解UML 及其软件开发方法的读者。

  二、基于UML的软件开发过程

  虽然UML是独立于软件开发过程的,即UML能够在几乎任何一种软件开发过程中使用,但是熟悉一种有代表性的面向对象的软件开发过程,并知悉UML 各语言要素在过程中不同阶段的应用,对于理解UML将大有裨益。

  图 5-2-6表示一种迭代的渐进式软件开发过程,它包含4个阶段:初启、细化、构造和移交。



图 5-2-6 面向对象的迭代、渐进式软件开发过程

  1.初启

  在初启阶段,软件项目的发起人确定项目的主要目标和范围,并进行初步的可行性分析和经济效益分析。

  2.细化

  细化阶段的开始标志着项目的正式确立。软件项目组在此阶段需要完成以下工作:

  (1)初步的需求分析。采用UML的用例描述目标软件系统所有比较重要、比较有风险的用例,利用用例图表示参与者与用例以及用例与用例之间的关系。采用UML 的类图表示目标软件系统所基于的应用领域中的概念之间的关系。这些相互关联的概念构成领域模型。领域模型一方面可以帮助软件项目组理解业务背景,与业务专家进行有效沟通;另一方面,随着软件开发阶段的不断推进,领域模型将成为软件结构的主要基础。如果领域中含有明显的流程处理成分,可以考虑利用 UML的活动图来刻画领域中的工作流,并标识业务流程中的并发、同步等特征。

  (2)初步的高层设计 。如果目标软件系统的规模比较庞大,那么经初步需求分析获得的用例和类将会非常多。此时,可以考虑根据用例、类在业务领域中的关系,或者根据业务领域中某种有意义的分类方法将整个软件系统划分为若干包,利用UML的包图刻画这些包及其间的关系。这样,用例、用例图、类、类图将依据包的划分方法分属于不同的包,从而得到整个目标软件系统的高层结构。

  (3)部分的详细设计 。对于系统中某些重要的或者比较高的用例,可以采用交互图进一步探讨其内部实现过程 。同样 ,对于系统中的关键类,也可以详细研究其属性和操作,并在UML 类图中加以表现。因此,这里倡导的软件开发过程并不在时间轴上严格划分分析与设计、总体设计与详细设计,而是根据软件元素(用例、类等)的重要性和风险程度确立优先细化原则,建议软件项目组优先考虑重要的、比较有风险的用例和类,不能将风险的识别和解决延迟到细化阶段之后。

  (4)部分的原型构造。在许多情形下 ,针对某些复杂的用例构造可实际运行的耐用消费品型是降低技术风险、让用户帮助软件项目组确认用户需求的最有效的方法 。为了构造原型 ,需要针对用例生成详尽的交互图,对所有相关类给出明确的属性和操作定义。

  综上所述,在细化阶段可能需要使用的UML 语言机制包括:描述用户需求的用例用用例图、表示领域概念模型的类图、表示业务流程处理的活动图、表示系统高层结构的包图和表示用例内部实现过程的交互图等。

  细化阶段的结束条件是,所有主要的用户需求已通过用例和用例图得以描述;所有重要的风险已被标识,并对风险应对措施了如指掌;能够比较精确地估算实现每一用例的时间。

  3.构造

  在构造阶段,开发人员通过一系列的迭代完成对所有用例的软件实现工作,在每次迭代中实现一部分用例。以迭代方式实现所有用例的好处在于,用户可以及早参与对已实现用例的实际评价,并提出改进意见。这样可有效降低大型软件系统的开发风险。

  在实际开始构造软件系统之前,有必要预先制定迭代计划。计划的制定需遵循如下两项原则:

  (1)用户变为业务价值较大的用例应优先安排;

  (2)开发人员评估后认为开发风险较高的用例应优先安排。

  在迭代计划中,要确定迭代次数、每次迭代所需时间以及每次迭代中应完成(或部分完成)的用例。

  每次迭代过程由针对用例的分析、设计、编码、测试和集成 5个子阶段构成。在集成之后,用户可以对用例的实现效果进行评价,并提出修改意见。这些修改意见可以在本次迭代过程中立即实现,也可以在下次迭代中再予以考虑。

  构造过程中,需要使用UML 的交互图来设计用例的实现方法。为了与设计得出的交互图协调一致,需要修改或精化在细化阶段绘制的作为领域模型的类图,增加一些为软件实现所必需的类、类的属性或方法。

  如果一个类有复杂的生命周期行为,或者类的对象在生命周期内需要对各种外部事件的刺激作出反应,应考虑用 UNL状态图来表述类的对象的行为。

  UML的活动图可以在构造阶段用来表示复杂的算法过程和有多个对象参与的业务处理过程。活动图尤其适用于表示过程中的并发和同步。

  在构造阶段的每次迭代过程中,可以对细化阶段绘出的懈图进行修改或精化,以便包图切实反映目标软件系统最顶层的结构划分状况。

  综上所核对,在构造阶段可能需要使用的UML语言机制包括:

  用例及用例图。它们是开发人员在构造阶段进行分析和设计的基础。

  类图。在领域概念模型的基础上引进为软件实现所必需的类、属性和方法。

  交互图。表示针对用例设计的软件实现方法。

  状态图。表示类的对象的状态—事件—响应行为。

  活动图。表示复杂的算法过程,尤其是过程中的并发和同步。

  包图。表示目标软件系统的顶层结构。

  构件图。

  部署图。

  4.移交

  在移交阶段,开发人员将构造阶段获得的软件系统在用户实际工作环境(或接近实际的模拟环境)中试运行,根据用户的修改意见进行少量调整。

第三节 基于UML的需求分析

  在初步的业务需求描述已经形成的前提下 ,基于UML的需求分析大致可分为以下步骤:

  (1)利用用例及用例图表示需求 。从业务需求描述出发获取执行者和场景;对场景进行汇总、分类、抽象;形成用例;确定执行者与用例、用例与用例图之间的关系,生成用例图。

  (2)利用包图及类图表示目标软件系统的总体框架结构 。根据领域知识、业务需求描述和既往经验设计目标软件系统的顶层架构;从业务需求描述中提取“关键概念” ,形成领域概念模型 ;从概念模型和用例出发,研究系统中主要的类之间的关系,生成类图。

  上述两个步骤并没有时序关系,它们可以并行展开,如图5-3-1所示。



图 5-3-1 需求分析过程

  本节将依次介绍上述步骤中涉及的UML语言机制,并结合“家庭保安系统”实例说明每步骤中基于UML的需求分析方法。

  一、开发场景

  场景是指从单个执行者的角度观察目标软件系统的功能和外部行为。这种功能通过系统与用户之间的交互来表征。因此也可以说,场景是用户与系统之间进行交互的一组具体的动作。相对于用例(见第五章第二节)而言,场景是用例的实例,而用例是某类场景的共同抽象。

  对场景的完整描述应包含场景名称、执行者实例,前置条件、事件流和后置条件。

  例如,“家庭保安系统”的初步需求描述:“家庭保安系统”的软件允许用户在安装时进行系统配置,实施对传感器的监控并通过控制面板与用户进行信息交互。

  配置操作包括:

  (1)指定每一传感器的种类和编号;

  (2)设置开、关机密码;

  (3)指定报警电话电码;

  (4)指定报警延迟和电话重拨延迟时间(以秒为单位);

  当软件系统收到传感器发出的数据后,判别是否出现异常事件。如果是,则在指定的延迟时间内拨报警电话号码,拨号操作将按照重拨延迟反复进行,直至电话接通。然后软件系统负责报告时间、地点和异常事件的性质。

  开机后,软件系统负责显示当前工作状态,接收并处理用户指令。

  根据以上描述,该系统具有“系统配置” 、“开机” 、“关机”、“门窗监测”、“烟雾监测”和“复位”等场景。其中,门窗监测场景的具体描述如下:

  场景名称:门窗监测。

  参与执行者实例:警报器、报警电话、显示器和门窗监视器。

  前置条件:系统已开机。

  事件流:

  (1) 门窗监视器发现门或窗户发生异动,向软件系统报告异常事件。

  (2) 软件系统启动警报器并拨报警电话号码。

  (3) 报警电话接通后,软件系统播出语音,报告异常事件发生的时间、地点和事件的性质(门窗异动)。

  (4) 系统在控制面板的显示器上显示报警时间及当前状态(报警:门窗异动)。

  后置条件:系统处于“报警”状态。

  根据场景作用的不同,可以将其划分为以下类型:

  (1)实际场景。 对实际的业务处理流程或其优化流程的描述。实际场景是用户需求的重要组成部分。

  (2)设想场景。 分析人员对目标软件系统投入应用后经改进或优化的业务流程的描述。这种场景可视为一种纸面原型,主要用于帮助分析人员挖掘潜在的用户需求。

  (3)评价场景。 以确认需求或提出改进建议为主要目的的业务流程描述。评价场景可以在用例生成后用例进行实例化而形成,以便用户对用例进行评价或改进。

  (4)培训场景。 面向开发人员及用户解释系统的功能和外部行为的业务流程描述。

  对以下问题的回答有助于分析人员获取场景:

  (1) 目标软件系统有哪些执行者?

  (2) 执行者希望系统执行哪些任务?

  (3) 执行者希望获得哪些信息?这些信息由谁生成?由谁修改?

  (4) 执行者需要通知系统哪些事件?系统响应这些事件时会表现出哪些外部行为?

  (5) 系统将通告执行者哪些事件?

  总之,确定执行者和场景的关键在于理解业务领域和初步需求描述文档。场景将促成开发人员和用户对业务处理流程和目标软件系统的功能范围的共同理解。在场景确定之后,通过对场景的汇总、分类归并和抽象即可形成用例。

  二、生成用例

  从外部用户的视角看 ,一个用例是执行者(actor)与目标软件系统之间的一次典型的交互作用。从软件系统内部的视角出发,一个用例代表系统执行的一系列动作,动作执行的结果能够被外部的执行者所察觉。执行者是指外部用户或外部实体在系统中扮演的角色。如果多个用户在使用目标软件系统时扮演同一角色,这些用户将由单一执行者表示。反之,如果一个用户扮演多种角色,则需要用多个执行者来表示同一用户。

  对用例的完整描述包括用例名称、参与执行者、前置条件、一个主事件流、零到多个辅事件流和后置条件。主事件流表示正常情况下执行者与系统之间的信息交互及动作序列,辅事件流则表示特殊情况或异常情况下的信息交互及动作序列。显式地分隔主、辅事件流是为了使分析人员首先聚集于正常的业务处理流程,同时也便于用例的读者理解业务需求。

  用例主要来源于分析人员对场景的分类和抽象,即将相似的场景进行归并 ,使一个用例可以通过实例化和参数调节而涵盖多个场景 。例如,“家庭保安系统“中的“开机”、“关机”、“复位” 3个场景可以归并为“命令处理”,3 个场景之间的差异通过用户命令种类的不同而体现。类似地,“门窗监测”、“烟雾监测”两个场景也可归并为统一的“传感器监测”用例 。其实 ,对于熟悉业务领域的分析师而言,也可以略过场景,直接从业务需求描述中获取用例。

  在“家庭保安系统”中,执行者有“用户”、“传感器”、“报警电话”和“显示器” ,用例有“系统配置” 、“命令响应”和“传感器监测”。下面以“传感器监测”为例说明用例的一般描述格式:

  用例名称:传感器监测。

  参与执行者:各类传感器、警报器、报警电话和显示器。

  前置条件:系统已开机。

  主事件流:

  (1)传感器向目标软件系统上报其监测数据 ,系统判别监测数据是否正常。

  (2)如果不正常,系统启动警报器,拨报警电话号码。

  (3)报警电话接通后 ,软件系统播出语音,报告异常事件发生的时间、地点和事件的性质。

  (4)系统在控制面板的显示器上显示报警时间及当前状态(报警)。

  辅事件流:

  (1)如果报警电话无人接听 ,则按照重拨延迟反复拨号,直至电话接通,再转入主事件流的步骤(3)。

  (2)如果重拨次数达到系统预设的最大次数 ,电话仍无人接听,则跳过主事件流的步骤(3),转入步骤(4)。

  后置条件 :如果已发现异常监测数据 ,系统处于“报警“状态;否则,系统处于正常的监测状态。

  三、用活动图表示用例

  用例的描述既可采用自然语言,也可采用活动图。后一种表示法更为精确和直观。下面首先介绍活动图的语法机制,然后结合实例说明如何用活动图表示用例。

  1.UML活动图

  用例的事件流或操作均表示为一系列的活动,每个活动在活动图中被表示为一个节点。节点之间的有向边表示活动的执行顺序。在节点间的连接边上可以附加条件表达式,以表示在有向边的源节点执行完成后,如果条件成立 ,则开始执行有向边的目标节点所表示的活动 ;如果条件不成立,则目标节点的活动不被执行。条件表达式一般出现在以菱形为源节点的有向边上。菱形在活动图中属特殊节点,用来表示条件判断。例如,在图 5-3-2中,“密码验证”活动的有向边上。如果“(密码正确)”,则开始“开始选择功能”活动;否则,回到“输入密码“活动。

 

图 5-3-2 典型的活动图

  活动图还可以表示处理过程的并发。活动图的同步条(水平或垂直粗线)可以将一条有向边分叉为多个并发执行的分支进程,或将多个有向边上的进程同步合并为一个进程。例如,在图 5-3-2中,当用户选择取款操作,输入取款金额,且系统验证其要求的金额小于等于余额之后,系统分叉为两个并发进程:点钞、出钞和扣减余额、打印交易信息。此后,再合并为一个进程,进行“选择功能”活动。

  为了描述活动的责任对象,活动图引进了“泳道”的概念。泳道是由垂直长线分割出来的矩形区域,在泳道上方的对象负责该矩形区域内的所有活动。例如,在图 5-3-2中,类“ Customer ”的对象负责“插入银行卡”、“输入密码” 、“选择功能”和“输入金额” 4 项活动,其余活动由类“ATMsystem”的对象负责。

  2.用例的活动图表示

  针对前面所述的“传感器监测”用例,其活动图表示如图5-3-3所示。

 

图 5-3-3 “传感器监测”用例的活动图表示

  四、生成用例图

  执行者与用例之间的关系有两例种:触发执行与信息交换。执行者与用例之间可能兼具这两种关系,例如,“ 在家庭保安系统 ”中,执行者“用户”在触发用例“命令响应”的同时,还要向用例传送命令信息。

  在 UML用例图中,从执行者指向用例的边表示触发执行和/或信息交换,从用例指向执行者的边则表示用例将其生成的信息传递给执行者。

  UML的用例与用例之间存在如下两种关系:

  (1) 使用(use)关系 。如果有一个公共的动作序列存在于多个用例中,为避免重复,并使需求模型更简洁,可以将公共动作序列抽出来构成新的独立用例。这样,原来的多个用例与新的用例之间便通过使用关系来连接。例如,在“家庭保安系统”中“系统配置”和“命令响应”两个用例使用公共的“密码验证”子用例。

  (2) 扩展(extend)关系。如果一个用例的动作序列完全包含另一个用例的动作序列,且前者含有后者所不具备的一些特殊情况下的处理动作,则称前者扩展后者。例如,图 5-3-4的“传感器监测”用例仅包含正常的处理流程,而“报警电话未接通”用例除正常流程处还增加了“重复拨号”以及“重拨次数达到最大次数仍无人接听”这两种异常处理动作。

 

图 5-3-4 “家庭保安系统”的用例图

  五、建立顶层架构

  顶层架构的 主要目的是为后续的分析 和设计活动建立一种结构和分划 ,以便开发人员在不同的开发阶段 ,以及同一开发阶段的不同开发人员,能够聚焦于系统的不同部分。顶层架构是分析和设计的阶段成果的承载体。随着开发过程的推进,框架中的内容不断丰富、翔实,最终演进为完整的面向对象软件结构。

  UML 包图是表示顶层架构的适当机制,因此,下面首先介绍包图的语法机制,然后探讨建立顶层架构的方法与原则。

  1.UML包图

  包是UML 对类进行分组的一种机制。可以从某种视角将具有比较密切的关联的一些类划分为一个包,分属于不同包的两个类之间的关联则比较松散。由此可见,对于大型软件系统而言,包的划分是实现“分而治之”的重要技术手段。

  包之间存在两种关系:依赖和构成。如果对类A的修改将导致类B的改变,则称B依赖于A。如果两个包中存在具有依赖关系的两个类,则认为这两个类分属的包之间存在依赖关系。例如,图 5-3-5中的“订单”包依赖于“ 客户 ”包。包的构成关系是指包是可以嵌套的,即包中不仅可包含类,还可以包含子包。在图 5-3-5中,“领域”包由“订单”和“客户”两个子包构成。图 5-3-5中,“数据库接口”类仅定义抽象的数据访问、数据操作的接口函数,而“Oracle接口” 包和“DB2接口”包则基于具体的数据库管理系统逐一实现了通用接口中定义的抽象接口函数。

 

图 5-3-5 包图示例

  为了表示软件架构,还需要在包之间引进一种称为“连接器”的边。连接器用来表示包之间的信息传递、事件发送和软件调用等关系,且有单向和双向(即无向)之分。

  2.软件顶层架构的设计

  建立软件系统顶层架构的基本方法是,结合实际需求,从既往的架构设计经验模型中选取适当者,再进行微调或局部改造。目前有如下几种主要的架构模式:

  (1)流程处理模式 。流程处理系统以算法和数据引进中心,其系统功能由一系列的处理步骤构成,相邻的处理步骤之间以数据流通管道相互连接。

  图5-3-6表示具有3处理步骤的流程处理模式。这些处理步骤都使用公共的系统服务(例如数据库访问服务),处理命令来自用户界面,处理的进度和结果也通过用户界面呈现。

 

图 5-3-6 流程处理模式

  流程处理模式仅适合于采用批处理方式的软件系统,不适合于交互式系统。

  (2)客户/服务器模式。如图5-3-7所示,客户端负责用户输入和处理结果的呈现,服务器端则负责后台的业务逻辑处理。

 

图 5-3-7 客户/服务器模式

  (3)模型—视图—控制器(MVC)模式。如图 5-3-8所示,该模式将整个软件系统划分为模型,视图和控制器 3个部分。模型负责维护并保存具有持久性的业务数据,实现业务处理功能,并将业务数据的变化情况及时通知视图;视图负责呈现模型的业务数据,响应模型变化通知,更新呈现形式,并向控制器传递用户的界面动作;控制器负责将用户的界面动作映射为模型中业务处理功能并实际调用之,然后根据模型返回的业务处理结果选择新的视图。MVC模式特别适合于分布应用软件,尤其是Web应用系统。

 

图 5-3-8 模型-视图-控制器模式 


  (4)分层模式。如图5-3-9所示,分层模式将整个软件系统分为若干层次,最顶层直接面向用户提供软件系统的操作界面,其余各层为紧邻其上的层次提供服务。层次划时分的主要原则是:较易变化的软件部分(例如用户界面、与业务逻辑紧密相关的部件)置于较高层次,较稳定的软件部分(例如公共的技术服务部件)则位于较低层次;每一层次尽量只访问其紧邻下层提供的服务,避免越级访问,尤其要避免逆向访问(上层模块为下层模块提供服务);在许多情况下,可以将目标软件系统的外部接口置入较低层次,目标软件系统其余部分对外部系统的访问或操作均通过这些外部接口所提供的公共服务来完成。分层模式可以有效地降低软件系统的耦合度,因此其应用十分普遍。

 

图 5-3-9 分层模式

  在全面了解软件架构样式的前提下,对于具体的应用需求而言,影响顶层架构选取的主要因素在于分析人员的经验以及他们对每种架构样式与当前软件项目之间匹配程度的判断。事实上,大型软件的顶层架构往往需要复合使用多种架构样式。例如,整个目标软件系统采用分层结构,在系统的不同层次内再分别使用适宜的其他种类的架构模式。

  在确立顶层架构的过程中,需综合考虑以下因素:

  (1)架构中包的数量。 原则上,如果每个包中包含的软件元素(例如类)的数量过多,应考虑将其进一步细分;如果过少,则说明架构过早地陷入了细节,架构划分返工的可能性较大,同时也不合理地限制了后续分析和设计活动的自由空间。

  (2)架构中包之间的耦合度。 包之间的依赖关系和连接关系应尽量简单、稀疏,例如,在分层结构中,通常要求某一层中的软件元素只与同层及相邻下一层的元素之间存在依赖关系。

  (3)软件元素的稳定性。 要尽量抽取不稳定的软件元素之中相对稳定的部分将不稳定的软件元素分类聚集于少数几个包中,以提高软件系统的可维护性。

  (4)软件元素的必然性。 可以将可选功能和必须实现的功能分置于架构中不同的包或子包之中。

  (5)作为软件系统运行环境的物理网络拓朴。 根据软件元素在分布环境的部署情况区分顶层架构中的包,可以使包之间的消息传递与物理节点之间的通信相吻合,使后续的分析和设计活动受益于顶层架构中明确定义的通信关系。

  (6)软件元素的安全、保密级别。 根据安全访问的权限划分顶层架构中的包或者子包。

  (7)开发团队的技术专长。 根据开发人员在问题领域和软件技术领域不同的专长划分顶层架构中的包,使每个包都能分配给最适合的开发人员进行后续的分析、设计、编码和测试等,从而有利于并行开发。

  六、建立领域概念模型

  在用户需求和相关的业务领域中,往往有一些全局性的概念对于理解需求至关重要。因此 ,有必要抽取这些概念 ,并研究这些概念之间的关系。

  1.UML类图

  在UML中,用类表示概念,用类图表示领域概念模型。

 

图 5-3-10 类的表示图元

  UML的类包含3个部分:类的名称、属性列表和方法列表,其表示图元如图5-3-10所示。在需求分析的早期不需要一次性列举类的所有属性和方法。刚开始可以仅标识类名,以后随着分析、设计的不断推进而逐步完善属性列表和方法列表。

  在UML中,类之间的关系的主要有继承、聚集、关联和依赖。

  继承关系表示子类重用父类的属性的操作,子类的对象也是父类的对象,有时也称父类是子类的泛化(generalization)。

  例如,在课程管理系统中,“教务管理人员”、“学生”和“老师”都是泛化的“用户”类的子类,它们继承来自“用户”类的用户姓名、标识码、密码等属性以及用户注册、密码验证、退出系统等操作。

  类之间的聚集关系是对现实世界中部分—整体关系的直接模拟。 UML将聚集关系进一步细分为普通聚集和构成关系两种。在普通聚集关系中,一个部件类对象可同时参与多个整体类对象,构成关系则限定一个部件类对象在任意时刻只能参与一个整体类对象,部件类对象与整体类对象共存亡。普通聚集和构成关系的表示图元如图5-3-11所示。



图 5-3-11 普通聚集和构成关系的表示图元

  在概念上,关联关系表示两个类之间的相关性。从软件设计和实现的角度看,关联关系表示在两个类的对象之间存在着一种用于消息传递的稳定通道。例如,在课程注册管理系统中,“学生”类、“老师”类与“课程设置”类之间存在关联关系,因为“课程设置”肯定与选课学生和授课老师有关,学生和教师他都需要查询课程设置中有关信息,如上课时间、地点和选课学生清单等。

  参与聚集、构成和关联关系的两个类的对象之间往往存在着数量对应关系,这种关系是业务规则的具体表现。因此,当分析和设计推进到一定阶段之后,应该将这种数量对应关系在这三种关系的表示边上明确地标示出来。例如,图 5-3-2表示对于每个“课程设置”对象,选课学生应不少于10个,不多于50个。每个学生在一个学期中所选的课程应不少于 4门、不多于8门。

  依赖关系是关联关系的弱化 ,表示被依赖的 类的变化会影响到依赖类。依赖关系的起因有:依赖类的对象需要向被依赖害的对象传递消息;被依赖类作为依赖类的操作的形参类型。前一种情况不仅可以且依赖关系实现,也可以用关联关系及强化形式(聚合和构成)来实现。这两种实现方法的区别在于,依赖关系仅表示一种临时性的消息传递通道,一旦依赖类对象的操作完成,该通道立即消失;关联关系及其强化形式则表示消息传递通道在整个对象的生命周期中稳定存在。例如,在图 5-3-5中,“订单”包中的类仅依赖于“数据库接口”包中的类(接口),并不需要在它们之间建立关联关系,因为对数据库的访问和操作仅在订单处理类的函数中局部进行。

  综上所述,关联是依赖的强化,聚合是关联的强化,构成是聚合的强化。

  2.领域概念模型的建立

  为建立以UML 类图表示的领域概念模型,必须首先标识关键概念。关键概念的来源包括:

  业务需求描述和用例说明;

  业务领域中的相关规范、标准和术语定义;

  反映业务领域知识的既往经验;

  例如,“家庭保安系统”的领域概念模型如图5-3-12所示。



图 5-3-12 “家庭保安系统”的领域概念模型

  图5-3-12中新引入了“用户命令处理器”、“系统配置管理器”、监测器“异常事件” 和 “日志管理器” 5个新类。其中,“用户命令处理器”负责接收来自用户的操作命令,并将命令处理结果反馈至显示面板;“系统配置管理器”保存系统的配置信息,协助“用户命令处理器”完成用户对系统配置信息的修改,还要负责向系统中的其他类提供配置信息的查询服务;“监测器”负责接收传感器的数据,根据系统配置信息判别异常状况,在异常发生时生成“ 异常事件 ”对象,触发警报器并拨报警电话;“日志管理器”向系统中的其他类提供日志的记录和查询服务,日志信息应包括用户命令及处理结果、配置更改的历史记录和异常善的历史记录等。

 

转载于:https://www.cnblogs.com/ziizz/p/6026381.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js防篡改对象之冻结对象

const person {name: 啦啦德玛西亚,_job: 无业}Object.defineProperty(person, job, {get: function() {return this._job},set: function(newValue) {this._job newValue}})console.log(Object.isFrozen(person))// false//使用Object.freeze()将对象修改为冻结对象&#xf…

libinject的编译

libinject是一个Android进程注入实例,其下载地址为:http://download.csdn.net/download/ljhzbljhzb/3680780 libinject的编译需要NDK开发环境,在NDK安装成功之后,可以先将其自带的实例中的HelloJni导入到eclipse中,编译…

Boost - 序列化 (Serialization)

From: https://blog.csdn.net/zj510/article/details/8105408 程序开发中,序列化是经常需要用到的。像一些相对高级语言,比如JAVA, C#都已经很好的支持了序列化,那么C呢?当然一个比较好的选择就是用Boost,这个号称C准…

Linux Supervisor 守护进程基本配置

supervisor:C/S架构的进程控制系统,可使用户在类UNIX系统中监控、管理进程。常用于管理与某个用户或项目相关的进程。 组成部分supervisord:服务守护进程supervisorctl:命令行客户端Web Server:提供与supervisorctl功能相当的WEB操…

ES6使用object的is()方法比较两个值

此前js比较两个值是否相等时,一般使用 或 符号,我之前倾向使用后者,因为可以避免比较时触发强制类型转换,但某些情况使用 依然有问题,比如再比较NaN NaN时,返回的是false,需要使用isNaN()才能…

关闭子窗口 父窗口自动刷新

function clsoseForm(){window.opener.location.hrefwindow.opener.location.href; window.opener.location.reload();window.close();}转载于:https://blog.51cto.com/congwa/1199250

使用vue的sync修饰符进行子父组件的数据绑定

官方文档 父组件代码 <template><div><input type"button" value"我是父组件的按钮" click"show" /><!-- 在需要子组件修改的数据后加上.sync即可 --><child :isShow.syncisShow v-show"isShow" />&l…

三阶魔方还原公式

From: https://www.cnblogs.com/zqifa/p/mofang-1.html 1. 第二层棱块归位&#xff1a; 2. 顶层十字 3. 顶层棱中间块归位 这一步的目的是使顶层的4个棱中间块全部归位。 转动顶层(U)&#xff0c;若可以使一个棱中间块归位(如下图左&#xff0c;这里以[红-黄]块为例)&#x…

选项板概述

2019独角兽企业重金招聘Python工程师标准>>> 1、选项板概述 选项面板是一个包括一个或多个选项卡(Tab)&#xff0c;同一时刻只显示一个选项卡的这种用户界面。比如下图的IE选项设置界面中&#xff0c;就是一个选项板的应用&#xff0c;选项板上有“常规”、“安全”…

Vue 跳转相同路由携带不同参数,而页面不刷新

由于组件是复用的&#xff0c;若要对路由参数的变化作出响应的话&#xff0c;就需要在此组件上使用 watch&#xff08;监测变化&#xff09; $route 对象 created() {this.listQuery.code this.$route.query.id;this.getList();},watch: {$route(to, from) {//当参数改变时就会…

三阶魔方的入门教程

From: http://www.rubik.com.cn/beginner.htm 下面是三阶魔方图文教程&#xff0c;想直接看更好懂的三阶魔方视频教程请点这里 魔方别看只有26个小方块&#xff0c;变化可真是不少&#xff0c;魔方总的变化数为 或者约等于4.31019。如果你一秒可以转3下魔方&#xff0c;不计重…

oracle技术之查询初始化参数的方法(六)

查询初始化参数的方法很多&#xff0c;比如SHOW PARAMETER&#xff0c;或查询V$PARAMETER等&#xff0c;这里简单总结一下。这一篇描述CREATE PFILE的方法检查初始化参数。前面介绍了很多种方法&#xff0c;这些方法都是在数据库中查询初始化参数的设置。其实还有一种方法更加的…

MySQL LIST分区(转载)

LIST分区和RANGE分区非常的相似&#xff0c;主要区别在于LIST是枚举值列表的集合&#xff0c;RANGE是连续的区间值的集合。二者在语法方面非常的相似。同样建议LIST分区列是非null列&#xff0c;否则插入null值如果枚举列表里面不存在null值会插入失败&#xff0c;这点和其它的…

vue组件化通信之父向子传值

vue组件化通信之子向父传值 vue组件化通信之兄弟组件传值 父向子组件传值 常用的方法主要有三种&#xff1a;props、$refs、$children 建议使用前两种 使用props进行传值 parent.vue <template><div><childTest :msgmsg></childTest></div> …

Openssl的证书格式转换

PKCS 全称是 Public-Key Cryptography Standards &#xff0c;是由 RSA 实验室与其它安全系统开发商为促进公钥密码发展而制订的一系列标准。PKCS 目前共发布过 15 个标准。常用的有&#xff1a;1. PKCS#7 Cryptographic Message Syntax Standard2. PKCS#10 Certification Requ…

啦啦

Y2错题解析 数据流程图描述信息的来龙去脉和实际流程&#xff0c;反映信息在系统中流动、处理和存储的情况。程序结构图用来描述程序结构&#xff0c;一般由构成系统的要素和表达要素间关系的连线或箭头构成。因果图是一种发现问题“根本原因”的分析方法。 Spring依赖检查的常…

身份证号码格式验证

From: https://www.cnblogs.com/chenhaoyu/p/6189207.html /*** 验证身份证号码真伪* param $id* return bool*/ function checkIDCard( $id ) {$id strtoupper($id);$regx /(^\d{15}$)|(^\d{17}([0-9]|X)$)/;if(!preg_match($regx, $id))return false;$arr_split [];if(15 …

vue组件化通信之子向父传值

vue组件化通信之子向父传值 vue组件化通信之兄弟组件传值 vue中子向父传递消息一般使用$emit&#xff0c;方法比较简单&#xff0c;直接看代码 父组件 <template><div><childTest msgmyMsg></childTest>{{msg}}</div> </template><s…

冒泡排序 C#

主程序入口class Program{static void Main(string[] args){int[] iArrary new int[] { 1, 5, 13, 6, 10, 55, 99, 2, 87, 12, 34, 75, 33, 47 };//定义数组BubbleSorter sh new BubbleSorter();sh.Sort(iArrary);for (int m 0; m < iArrary.Length; m)//输出结果Console…

emacs 入门教程,菜单汉化,配置文件等杂乱文章

首先来一发ArchWiki的Emacs简体中文的入门教程 https://wiki.archlinux.org/index.php/Emacs_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87) 怎样设置&#xff0c;Emacs中文菜单&#xff1f; 把包内的3个文件丢到 emacs/share/emacs/site-lisp下面。 在&#xff5e;/ 建一个 .emacs的…