版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、软件工程,第4讲 软件设计,第4讲 软件设计,4.1 软件设计的任务、过程和原则 4.2 软件设计的基本概念和原理 4.3 面向数据流的结构化设计方法 4.4 数据设计 4.5 用户界面设计 4.6 软件过程设计 4.7 软件设计文档的内容及其复审的方法,4.1 软件设计的任务、过程和原则,软件设计的任务 分析、理解软件需求规格说明书(SRS),并将其转化为实际软件系统的一个模型或软件表示,即用于构造软件的“蓝图”。 形成必要的设计文档,包括:软件概要设计说明书,软件详细设计说明书,数据库设计说明书 软件设计的主要内容 主要包括:数据设计、体系结构设计、接口设计、过程设计等4个部分。,数据设计
2、 将实体关系图中描述的对象和关系,以及数据词典中描述的详细数据内容转化为数据结构的定义。 体系结构设计 定义软件系统各主要模块的功能及其之间的关系。 接口设计 根据数据流图定义软件内部各成份之间、软件与其它协同系统之间及软件与用户之间的交互机制。 过程设计 把结构成分转换成软件的过程性描述。在编码时,根据这种过程性描述,生成源程序代码,然后通过测试最终得到完整有效的软件。,软件设计与软件需求之间的关系:,软件设计可细分为两个阶段,概要设计:确定程序各主要部件之间的关系,给出能反映系统功能、数据、行为需求的软件的总的框架。 详细设计:对此框架中每一部件进行过程化描述,把它刻画为在细节上非常接近于
3、源程序的软件表示。,例如:机器人控制系统,为何要重视软件设计, 因为它与软件质量和用户需求息息相关,用户所有的需求都必须通过精心的设计来满足。 比如,如果信息安全是对用户的关键需求,那么体系结构设计时就应该采用分层结构,将重要资源放在内层,并在每层采用严格的安全性验证。 如果可用性是一个关键需求,则需要考虑冗余的体系结构设计,以便在无须系统停止的情况下更新或替换组件。 设计是所有后续工作的指南,编码实现必须以设计为前提和基础。,4.2 软件设计的基本概念和原理,1)模块化 模块化就是将大型软件按照规定的原则划分解成一个个较小的、相对独立的但又相互关联的模块的设计方法。 将系统分解成模块、对象和
4、构件等组成部分。在传统的软件工程中用分解来实现模块化设计;在OO软件工程中,靠分解来划分类和对象。,C(P1+P2) C(P1)+C(P2) E(P1+P2) E(P1)+E(P2),模块分解的程度 模块的分解不能太多也不能太少。,2)抽象 解决问题时只考虑与问题有关的方面,不考虑与问题无关的方面。即抽出事物的本质特性而不考虑细节。,3)信息隐藏 模块内部的数据与过程(操作),应该对不需要了解这些数据和过程(操作)的模块隐藏起来。 信息隐藏的目的 提高模块的独立性,减少把一个模块的错误扩散到其他模块中去的机会。 信息隐藏的例子 全局变量:任何函数都可以访问。 堆栈: 通过函数Push()、Po
5、p()、Clear() 操作栈 其他函数并需要、也不知道栈的具体情况。,4)软件复用 软件复用是指在两次或多次不同的软件开发过程中重复使用相同或相似软件元素的过程。 构件(component)可以复用的软件成分,可被用来构造其他软件。它可以是: 被封装的对象类 功能模块 软件架构(或体系结构Architecture) 设计模式等,5)模块独立性 模块独立性的度量:内聚度和耦合度 内聚:指模块内部各个成分之间的联系。也称:块内联系、模块强度。 耦合:指一个模块与其它模块之间的联系。也称块间联系。 模块独立性的度量准则: 块内联系程度越强、块间联系程度越弱,则模块的独立性越高。 模块独立性强的模块
6、的优点 降低复杂性,便于并行开发和实现 容易测试和维护,(1)内聚的分类,从功能的角度来看模块内部的聚合程度,可以按照由弱到强的顺序,把内聚分为7类。,低内聚,中内聚,高内聚,偶然 逻辑 时间 过程 通信 顺序 功能,偶然性内聚模块:即无任何联系。 块内各组成成分在功能上是互不相关的。 例如,“记录人员信息”和“产生公司财务报表”构成了一个模块。 逻辑性内聚模块:即有某种类型联系。 通常由若干逻辑功能相似的成分组成,每次调用由传给模块的参数确定执行哪种功能。 时间性内聚模块:即从时间方面看有联系。 这类模块所包含的成分在一个固定的时间点执行。 例如,一个初始化模块中的“为变量赋初值”、“打开文
7、件”等。,过程化内聚模块:即一组任务有次序的联系。 一个模块中包含的一组任务必须按照某一特定的次序执行。 例如, “读入炉温”-“记录炉温”-“比较温度”-“计算阀门开度”-“驱动阀门”等。 通信性内聚模块:即数据结构的区域联系。 模块内部的各个组成部分都引用一组相同的数据。 如下图的例子:,顺序性内聚模块:即有输入/输出的紧密联系。 模块中各组成部分密切相关且必须顺序执行,前一处理部分的输出就是下一处理部分的输入。 例如,排序程序:“读如一组整型数”-“对这组数从小到大排序”-“将排序后的这组数输出”。 功能性内聚模块:内聚性最强。即有功能的紧密联系。 一个模块中各个部分都是为完成一项具体功
8、能而协同工作,紧密联系,不可分割的. 例如,求一元二次方程ax2+bx+c=0的实根。 Root( a,b,c,X1,X2): 计算b2-4ac;sqrt(b2-4ac); X1=(-b+sqrt(b2-4ac)/2a;X2=(-b-sqrt(b2-4ac)/2a,设计时对模块内聚性的选择,“一个模块,一个功能”是模块化设计的一条准则,也是设计人员争取的目标。 功能性内聚模块是最理想的。 中、高内聚的模块也可使用。 低内聚模块的可维护性和可复用性差,设计时应尽量避免使用。,(2)耦合的分类,模块间的引用方式,数据量,数据格式,数据类型都对耦合的强度产生影响 按照影响程度耦合可分为7类,如下图所
9、示。,非直接 数据 特征 控制 外部 公共 内容,数据耦合 模块间通过参数表交换数据,且交换的都是数据项参数(而不是控制参数、公共数据结构或外部变量)。 数据耦合是松散的耦合,模块之间的独立性比较强。,非直接耦合 两个模块之间没有直接关系,相互之间没有信息传递,它们之间的联系完全是通过主模块的控制和调用来实现的。 这种耦合的耦合度最低,模块独立性最强。,特征耦合(也称标记耦合): 如果2个以上的模块都需要共享某一数据结构的子结构时,不能用全局变量的共享方式,而是采用记录传递方式。 例如,A调用B,向B传递某个人的记录(而B可能只需要记录中的几个数据项)。,控制耦合: 模块间传递的是用作控制信号
10、的开关值或标志。 这种耦合的实质是在单一接口上选择多功能模块中的某项功能。因此,对被控制模块的任何修改,都会影响控制模块。这也意味着控制模块必须知道被控制模块内部的一些逻辑关系,这些都会降低模块的独立性。,外部耦合: 允许一组模块访问同一个全局变量(单域变量)。 例如,C中的extern。 问题:当max的值发生错误时,是哪个函数造成的?,#define MAXLINE 1000 char line MAXLINE; char save MAXLINE; int max; main() int len; extern int max,line; extern int save; ,getlin
11、e() int c,j; extern char line; Copy() int j; extern char line,save; ,公共耦合 一组模块都访问同一个公共数据结构。 公共的数据结构可以是全局数据结构、共享的通信区、内存的公共覆盖区等。 公共耦合的复杂程度随耦合模块的个数增加而显著增加。只有在模块之间共享的数据很多,且通过参数表传递不方便时,才使用公共耦合。, 内容耦合 (1)一模块直接访问另一模块的内部数据 (2)一模块不通过正常入口转到另一模块内 (3)两模块有一部分代码重叠 (4)一模块有多个入口,一模块直接访问 另一模块的内部 信息 (程序代码 或数据),A,B,A,B
12、,模块代码重叠,Entry1 Entry1 ,多入口模块,设计时对模块耦合度的选择,耦合越弱,则模块的独立性越强,因此应尽量使用耦合度低的设计。 但实际开发软件系统时,中等或较强耦合是不可避免的,也不需要禁止使用。 最强耦合度的内容耦合,会给维护工作带来很大的困难,应该不用。,4.3 概要设计方法结构化设计方法,4.3.1 概要设计 概要设计应该包括两方面内容: ()产生一个模块化的程序结构,并明确各模块之间的控制关系, 亦称为系统结构; ()说明每个程序模块的输入输出数据结构。,软件设计从需求定义开始,逐步分层导出系统结构和数据结构,当需求定义中所述的每个部分最终都能由一个或几个软件元素实现
13、时,整个求解过程即告结束。,例如:机器人控制系统,依据不同软件设计方法总能推导出一个软件结构,对于同一问题的各种软件结构,4.3.2 面向数据流的结构化设计方法,结构化设计方法(SD)是以数据流图为基础的,它定义了把数据流图变换成软件系统结构的映射方法,所以这种方法也称为面向数据流的设计方法。 (1)主要任务,映射 DFD 软件系统的结构 (软件系统 (软件的 逻辑模型) 初始结构描述),(2) SD方法的设计过程,步1:鉴别DFD图所表示的软件系统的结构特征,确定它所代表的软件结构是属于变换型还是事务型; 步2:划分流界,按照SD方法规定的规则,把DFD图转换为初始的SC图;,步3. 根据设
14、计优化的指导原则改进初始SC图,生成最终的SC图。,(3) 数据流图的两种类型,变换型数据流图,变换 中心,输入 路径,输出 路径,(3) 数据流图的两种类型,事务型数据流图,输入边界,输出边界,(4)软件结构表示,4.1)层次图(HC),模块:用矩形表示 模块间的调用关系:用带箭头的连线表示 数据流:在调用关系线的旁边用命名的箭头表示 选择调用: 循环调用:,4.2)软件结构图(SC),(5)变换分析方法,5.1)划分边界,5.2)第一级分解(建立初始SC框架),5.3)第二级分解(建立每个分支的下级模型),传入分支的分解,传出分支的分解,加工中心的分解,(6)事务分析方法,6.1)在DFD
15、上确定事务中心、接收部分和发送部分。 6.2)画出SC框架,把DFD上的三部分分别映射为事务控制模块、接收模块和动作发送模块。 6.3)分解细化接收分支和发送分支,完成初始SC。,(7)结构设计案例:用户命令交互子系统,事务型设计,变换型设计(1),变换型设计(2),(8) 软件结构设计优化,保持高扇入/低扇出; 模块的作用范围应在其控制范围之内; 模块的控制范围(Scope of Effect) :由它本身及其所有的从属模块。 模块的作用范围(Scope of Control):由此模块的某些决定而影响的所有模块所组成。 可预测性:一个模块应该是可预测的; 输入恒定,输出则恒定,即“黑箱”概
16、念。 有必要的错误处理,高扇入/低扇出:上层高扇出,下层高扇入,模块的控制范围与其作用范围,模块F的控制范围: F、G、H、I,模块F的作用范围: B,错误处理示例,一种语言机制 模块: 正常处理部分; ; 当错误条件发生 启动例外处理过程; 例外处理过程 ; 例如,S ybase T-SQL Trigger Code,/* Insert trigger ti_store_account_history for table STORE_ACCOUNT_HISTORY */create trigger ti_store_account_history on STORE_ACCOUNT_HISTO
17、RY for insert asbegin declare numrows int,numnull int, errno int,errmsg varchar(255) select numrows = rowcount if numrows = 0 return /* Parent STORE_ACCOUNT must exist when inserting a child in STORE_ACCOUNT_HISTORY */ if update(GOODSID) begin if (select count(*) from STORE_ACCOUNT t1, inserted t2 w
18、here t1.GOODSID = t2.GOODSID) != numrows begin select errno = 30002, errmsg = Parent does not exist in STORE_ACCOUNT. Cannot create child in STORE_ACCOUNT_HISTORY. goto error end end return/* Errors handling */error: raiserror errno errmsg rollback transactionend,又例,MRP/ERP软件中入/出库处理 入库模块的一种处理方式: 录入产
19、品项目编号; 在产品清单中查找该产品项目编号; 如果存在 则 记入入库明细帐中; 更新库存总帐; 否则 按照该错误条件(编号) 查找错误信息表并获取信息; 启动例外处理过程; 例外处理过程 给用户显示错误信息; 返回录入界面; ,错误信息表,窗口的形状、位置、大小 文字的字体、大小、颜色,(1)数据库设计 概念设计 ER模型/EER模型 逻辑设计设计阶段的任务 把ER模型/EER模型转换成关系模型,用SQL表示 物理设计 借助于RDBMS的有关功能进行。 (2)数据结构设计,4.4 数据设计,数据库设计科借助于工具来完成 把ER模型/EER模型转换成关系模型,用SQL表示,/*= */ /*
20、Database name: SMSTORE_1 */ /* DBMS name: Sybase System 11 */ /* Created on: 2/25/2005 12:41 AM */ /* = */ /* Table: SUPPLIER */ create table SUPPLIER ( SUPPLIERID char(10) not null, SUPPLIERNAME varchar(40) null , JURISTICPERSON char(10) null , JURISTICPERSONRP char(10) null , IFSIGN bit null , SIG
21、NDATE datetime null , TEL varchar(30) null , ADDR varchar(60) null , TAXNO varchar(20) null , BANKNAME varchar(40) null , ACCOUNTS char(1) null constraint CKC_ACCOUNTS_SUPPLIER check (ACCOUNTS in (1,0), FAX varchar(20) null , constraint PK_SUPPLIER primary key (SUPPLIERID),数据结构设计示例: 设计一种好的数据结构,便于根据该
22、结构能快速查找中文的任意“词语”,4.5 接口设计,(1)用户界面设计的指导原则 分析用户类型 应用程序和界面分离 一致性 尽量减少用户记忆和工作量 可恢复性 出错处理和帮助功能 增加可视化图形表示,4.5.1 用户界面设计,系统内部模块接口、系统外部接口、人机界面,用户界面设计范例,(2)用户界面设计过程,用户、任务和环境分析及建模 用户类型通常分为:外行型、初学型、熟练型、专家型。 用户特性度量与用户使用模式和用户群体能力有关。包括:用户使用频度、用户用机能力、用户的知识、思维能力等。 界面设计 界面构造 界面确认,界面设计层次化任务分析HTA,层次任务分析HTA是用一种结构化的方法来分析
23、并描述用户如何为达到目标所进行的一系列任务,以及用户与软件系统是如何交互的。 通过层级分析将任务不断拆解,逐级细化用户的任务,直至用户实际的具体操作。随着任务的细化,我们对用户和产品的理解会越来越清晰。 例如:通过用户的任务分析,来设计一个网上书店,对“挑选图书”任务进行分解,继续对“搜索图书”细化,界面构造基于visio实现,1)过程设计的主要任务 过程设计就是在概要设计阶段的基础上,对各个模块给出确定采用的算法和模块内的数据结构,用某种表达工具给出清晰的过程描述。具体的任务有: 确定各个模块的算法;确定各个模块使用的数据结构;确定各个模块接口的细节; 编写详细设计说明书; 2)过程设计的目
24、的 为编码阶段的工作提供足够的依据,使其能够根据过程描述,快速地、几乎是机械地完成编码任务,同时也为测试工作打下基础。,4.6 软件过程设计,3)过程设计的基本原则 (1)运用结构化程序设计的思想 (2)遵循一些规则 使用三种基本结构 单入口/单出口 限制GOTO 使用统一的描述工具,如 FC 程序流程图 NS 盒图 PAD 问题分析图 PDL 程序设计语言,3)描述工具 FC程序流程图,NS 盒图 由Nassi和Shneiderman提出,因此而得名。,PAD 问题分析图 由Nassi和Shneiderman提出。,PDL 程序设计语言 PDL是一种用于描述功能模块的算法设计和加工细节的语言
25、,也称伪码(pseudo code)。 外层语法:符合一般程序设计语言常用语句的较严格的关键字语法规则,用于定义控制结构和数据结构。 内层语法:可以用英语中一些简单的句子、短语和通用的数学符号,来描述程序应执行的功能。,IF- THEN- ELSE- ENDIF DO-WHILE- ENDDO REPEAT-UNTIL- ENDREP CASE-OF- WHEN-CONDITION-SELECT- ENDCASE DECLARE AS STRING ARG AS ARRAY ARG,例 某系统主控模块的处理流程用PDL描述如下: PROCEDURE MAIN( ) 清屏; 显示xx系统用户界面
26、; 接收用户输入口令; IF 输入口令系统保存的口令 提示警告信息; 退出系统; ENDIF WHILE (.T.) 显示系统主菜单; ABC=接收用户选择; IF ABC = 退出 退出本循环; ENDIF 调用相应的下层模块完成用户选择的功能; ENDWHILE 清屏; RETURN END,例 某系统主控模块的处理流程用FC描述如下:,例 模块binary(x,v,n,p)完成判断一个特定值x是否出现在已经按递增顺序排好序的数组v中。如果存在则返回相应下标mid ,否则返回值-1。,Y,例 逐步求精方法示例:骑士周游问题。给出一块有n2个格子的棋盘。一位骑士放在初始坐标为(x0,y0)的
27、格子里,然后按照国际象棋的规则移动。问题是找到一种可以走遍整个棋盘的方案(如果这种方案存在),即计算一个n2-1次移动的周游,使得棋盘上每一个格子恰好被走过(访问过)一次。 (1)数据结构设计: 棋盘:用一个二维整型数组hi,j,I=1.n,j=1.n 马的移动位置:有8个可走位置。马的初始位置为(x,y),下一个移动位置(x+ak,y+bk),其中k=1.8。,X,0,棋盘格子h x,y是否被访问过,可以用下面的方式记录:,0表示格子 x,y未被访问过 i 表示格子 x,y在第i次移动中被访问过,1=i=n2,h x,y =,(2)算法设计:试探+回溯 步1:初始化; 步2:对给定的马的当前
28、位置 调用“试探下步移动”; 步3:if 下步移动成功 then 步3.1: 打印移动结果; else 步3.2: 打印无解 endif,步1的“初始化”工作可以细化为: 1.1马的8个可移动位置的差值分别按照前面表格中的值预先放在a、b数组中; 1.2 棋盘在马未访问过时应该都预先放入0; 1.3 马的最初位置可以是(1 ,1);此时该位置所确定的棋盘格子认为被访问过,因此应有h 1,1 =1。,(2)算法设计:试探+回溯 步1:初始化; 步2:对给定的马的当前位置 调用“试探下步移动”; 步3:if 下步移动成功 then 步3.1: 打印移动结果; else 步3.2: 打印无解。 en
29、dif,对于马的当前位置的下步移动应该有8个候选位置用K计数,候选次序是前面图示中的逆时针方向进行。一旦进入下一步即一个新的位置,同样又要“试探下步移动”。如果本步移动成功,那么返回“真”,否则返回“假”。因此是一个递归过程try(i,x,y,q) 。,“试探下步移动”可设为try(i,x,y,q) : 2.0 做候选准备; 2.1 repeat 2.1.1 从下一步移动表中挑选出下一步候选者; 2.1.2 if 候选者可接受 then 进行移动; endif 2.2 until 移动成功或再无候选者; 2.3 返回移动成功与否的标志.,马在当前位置而且在下步移动前,一个位置都没有试探过,因此
30、k值应为0。8个候选位置试探完毕时k值应为8。,“试探下步移动”还需要细化: 2.0 做候选准备; 2.1 repeat 2.1.1 从下一步移动表中挑选出下一步候选者 2.1.2 如果候选者可接受,则 2.1.2.1 进行移动; 2.2 until 移动成功或再无候选者; 2.3 返回移动成功与否的标志.,如果候选者的当前步为k,则候选者的下一步变为k+1。,那么,下一步的候选者“可接受”的条件应该是:u,v不能越界而且该步所处位置未被访问过,可表示为(1=u=n) and (1=v=n) and (hu,v=0),2.1.2.1“进行移动”可以进一步细化为: 记录移动; if 盘未走遍 t
31、hen “试探下步移动”即为递归调用步2; if “试探下步移动”不成功 then删去这一记录即回溯; else 用局部变量q1表示并赋true; endif endif,设挑出的下一步候选者为(u,v),则 u可用x+ak,v可用y+bk表示。,“移动成功”可把ture赋予局部变量q1; “再无候选者”意味着当前马的位置的下一步已经对可能的8个位置都试完了,因此可表示为k=8。,移动成功与否可把变量q1的值赋予变量q,2.1.2.1“进行移动”还需要细化: 记录移动; if 盘未走遍 then “试探下步移动”即为递归调用步2; if “试探下步移动”不成功 then删去这一记录; else
32、 给q1赋值true; endif endif,“记录移动”可以表示为: hu,v被赋予当前所试探的次数i。i是一个全局变量,“盘未走遍”可以表示为: in2,“试探下步移动”应该是一个递归调用,可以表示为: try(i+1,x,y,q1),“试探下步移动不成功”可以表示为:NOT q1,“删去这一记录”可以表示为: hu,v被赋予0,(2)算法设计:试探+回溯 步1:初始化; 步2:对给定的马的当前位置 调用“试探下步移动”; 步3:if 下步移动成功 then 步3.1: 打印移动结果; else 步3.2: 打印无解。 endif,步3中对“下步移动成功”的判断可以对步2中“试探下步移动
33、”即过程try(i,x,y,q)调用结果的返回值q作判断即可: q为true即为移动成功, q为false即为移动失败。,步3.1“打印移动结果”即输出数组hi,j 的各元素之值。其中i,j 的取值为1到n;,步3.2“打印无解”即是输出一个提示信息。,(2)算法设计的最后描述 步1:定义全局变量并初始化 PRAGRAM KNIGHTSTOUR DECLARE n:as integer; q:as boolean; GET(n); DO-WHILE i=n DO-WHILE j=n hi,j=0; j=j+1; ENDDO i=i+1; ENDDO; a1=2; b1=1; a2=1; b2=
34、2; a3=-1;b3=2; a4=-2;b4=1; a5=-2;b5=-1;a6=-1;b6=-2; a7=1; b7=-2;a8=2; b8=-1;,步2和步3 : h1,1=1; try(2,1,1,q) ;/调用过程try( i,x,y,q) 见后 IF q THEN DO-WHILE i=n DO-WHILE j=n PUT(hi,j); j=j+1; ENDDO 换行; i=i+1; ENDDO ELSE PUT( “打印无解”); ENDIF END PROG,PROCEDURE try(i,x,y,q) DECLARE i,x,y:as integer ARG; q:as bo
35、olean ARG;,k=0; REPEAT UNTIL k=8 or q1 k=k+1;q1= FALSE; u=x+ak;v=y+bk; IF (1un)and (1vn) and (hu,v=0) THEN try(i+1,u,v,q1) ; IF NOTq1 THEN hu,v=0 ELSE q1= TRUE; ENDIF ENDIF ENDREP q= q1; ENDPROC,处理编号:3(简单库存管理系统SMSTORE的一个处理描述) 处理名称:办理出库 接受的输入:出库单 产生的输出:仓库中无此货物,库存不够 读取的文件:货物清单 写或修改的文件:出库明细帐,库存帐 处理过程:
36、1)接受出库单; 2)根据出库单的基本信息,检查该出库单所列货物是否在仓库货物清单中存在 如果不存在,则 对出库员给出仓库中无此货物信息,结束处理。 3)根据出库单的基本信息,检查该出库单所列货物的数量在库存帐中是否够 如果不够,则 对出库员给出库存不够信息,结束处理。 否则 把出库单的基本信息写入出库明细帐; 根据出库单的基本信息修改库存帐中的库存量。 结束处理。 激发条件:当出库员收到出库单并进行登记时。,例 信息处理流程图示例,开始,结束,根据设定的出库单界面录入各项数据: OUTSTOREID、GOODSID、 SUPPLIERID、OUTDATE、 OUTPERSON、MANAGER、 QUANTITY、CLIENTNAME,根据录入的出库单中各货物的 GOODSID 检查“货物清单” GOODSLIST中是否存在,GOODSLIST,存在?,“仓库中 无此货物,根据出库单中各GOODSID的数量检查“库存帐” STORE_ACCOUNT中的库存量QUANTITY是否够. QUANTITY= STORE_ACCOUNT.EARLY_QUANTITY+ STORE_ACCOUNT.CURRENT_IN_QUANTITY- STORE_ACCOUNT.CURRENT_OUT_QUANTITY,S
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论