`
songlj
  • 浏览: 15924 次
社区版块
存档分类
最新评论

软件工程总结

 
阅读更多

面向对象的分析

概念:

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

对象的两个基本元素:属性和服务。属性是用来描述对象静态特征的一个数据项;服务是用来描述对象动态特征的一个操作序列。

对象是属性和服务的结合体,对象的属性值只能有这个对象的服务来读取和修改。

类:服务是用来描述对象动态特征的一个操作序列。类代表一个抽象的概念或事物,对象是在客观世界中实际存在的类的实例。

封装:把对象的属性和服务结合成一个独立的系统单位,并尽可能隐藏对象的内部细节。

继承:子类可以自动拥有父类的全部属性和服务。

消息:消息是对象发出的服务请求,一般包含提供服务的对象标识、服务标识、输入信息和应答信息等信息。

多态性:由于类的继承以及子类方法重载的存在,使得以父类作为形参的函数在运行时可能接受不同类型的实参。实参可能是:父类自身对象或者某个直接/间接子类的对象。多态提高了灵活性和可扩展性。

统一建模语言:

UML关系:

关联:是一种结构关系,描述一组对象之间的连接,关联两端的类可以某种角色参与关联。

聚合:是一种特殊形式的关联,它表示类之间整体和部分的关系,聚合的两端是“has a”关系。

组合:是一种特殊形式的关联,组合关系中的整体和部分具有同样的生存期,组合两端是“contains a”关系。


泛化:是一种特殊和一般的关系。

依赖:依赖是一种使用的关系,它说明一个事物的规格说明的变化可能影响到使用它的另一事物。依赖可能的原因:一个类向另一个类发消息;一个类是另一个类的某个操作参数。

实现:类元之间的语义关系,其中的一个类元指定了由另一个类元保证执行的契约。

类之间的四种关系:

分类关系、继承---泛化(一般和特殊)

静态联系----关联。

构成关系---聚合

构成关系---组合

使用关系----依赖

实现关系----实现

识别继承(泛化):

1)学习当前领域的分类学知识。
2)按常识考虑事物的分类。
3)利用泛化的定义。
4)考察类的属性与操作。
5)看两个类的对象之间是否有“是一种” 关系。

6)考虑领域范围内的复用。

一般特殊结构的简化:取消没有特殊性的特殊类、增加属性简化一般和特殊关系、取消用途单一的一般类,减少继承层次(一般类存在理由:有两个及以上特殊类、需要用它创建实例、有助于软件复用)。

对象之间的关系:对象之间的静态联系,最终可通过对象属性来表示一个对象对另一个对象的访问关系。对象之间的动态联系,对象在行为上(操作调用)的依赖关系。使用关联表示类之间的静态关系。

判断关联关系:如果类的对象之间通过属性有连接关系,那么这些类之间的语义联系就是关联。

用例图:用例图定义了系统的功能需求,它完全是从系统的外部观看系统功能,并不描述系统内部对功能的具体实现。用例图表示了用例、参与者及其它们之间的关系。符号:

参与者:参与者是与系统交互的外部实体,既可以是使用该系统的用户,也可以是与系统交互的其他外部系统、硬件设备或组织机构。参与者之间可以存在泛化关系,类似的参与者可以利用泛化关系组成一般与特殊的层次关系。如:


用例:是从用户角度描述的系统行为,它将系统的一个功能描述成一系列事件,这些事件最终对参与者产生有价值的可观测结果。用户之间的关系:包含关系、扩展关系、泛化关系。包含关系:指一个基本实例的行为包含另一个用例的行为,

即一个实例发生的话包含实例一定发生。

扩展关系:在用例执行过程中,可能会出现异常情况,也可能会在不同的流程分支中选择执行,这时可以将异常行为,可选分支抽象为一个单独的扩展用例。

基本用例发生,扩展用例不一定发生,是可选的。

泛化关系:描述用例之间的一般与特殊关系,不同子用例代表了父用例的不同实现方法。

时序图:描述了一组交互对象之间的交互方式,它表示完成某项行为的对象和这些对象之间传递消息的时间顺序。组成:对象(参与者实例也是对象)、生命线(对象存在的时间)、控制焦点(表示对象执行一个所经历的时间段)、消息(对象之间的通信)。

对象的创建和销毁:时序图中,对象是时序图的顶部说明对象再交互开始前就已经存在,若对象是在交互过程中创建的,则将对象放在图的中间。如果要销毁对象,只要在其生命线终点放一个“符号。

活动图:描述活动的顺序,展现从一个活动到另一个活动的控制流。如

UML图:

功能建模:用例图;

对象建模:类图;

动态建模:时序图、状态图和活动图。

面向对象分析

需求模型:系统边界、参与者、用况、用况图

例如:小型图书资料管理系统

建立需求模型:确定系统的参与者、确定系统用例、确定用例之间的关系、编写用例描述文档。

描述用况:用况描述---采用自然语言描述参与者与系统进行交互时双方的行为。用况描述的主要内容用例的目的、用例如何被启动、参与者与用例之间的事件流(基本流、可选流)、前置条件、后置条件、扩展点。说明---应该只描述可观测的结果、应该使用主动语句、句子的主语应该是参与者或者系统、不要涉及系统的实现细节、不要涉及界面细节。

研究生学籍管理系统为例:仅仅描述登陆、选课、查看学分三个功能。

较好方案:该方案的登录用况完全独立于其他用况,使用该方法,必须在“选课用况和查看学分用况中指定前置条件:只能在登录成功时才能执行自己。

基本模型:

类图:描述系统的静态结构,表示系统中的类、类与类之间关系以及类的属性和操作。在不同的开发阶段,类图具有不同抽象层次:需求阶段---概念型类图描述应用领域中的概念,这些概念与类有很自然的联系,但两者并没有直接的映射关系;设计阶段---说明层类图描述软件接口部分,而不是软件的实现部分;实现阶段:实现型类图才真正考虑类的实现问题,揭露软件的实现细节。

面向对象分析的概念:

分析类:在分析模型中,分析类是概念层次上的内容,用于描述系统中较高层次上的对象;分析类直接与应用逻辑相关,而不关注技术实现的问题。

分析类的类型:实体类(表示系统存储和管理的永久信息)、边界类(表示参与者与系统之间的交互)、控制类(表示系统在运行过程中的业务控制逻辑)。

控制类:描述一个用例所具有的事件流控制行为;实现对用例行为的封装,将用例的执行逻辑与边界和实体进行隔离。

识别边界类:通常,一个参与者与用例之间的交互或通信关联对应一个边界类。

注:边界类应关注参与者与用例之间的交互信息或者响应的事件,不要描述窗体组件等界面的组成元素。

识别控制类:控制类负责协调边界类和实体类,通常在现实世界中没有对应的事物

识别实体类:实体类通常是用例中的参与对象,对应着现实世界中的事物

建立分析类图

定义关系:找出分析类之间的关联关系,并通过泛化实现复用。

定义属性:按照一般常识找出对象的某些属性;认真研究问题域,找出对象的某些属性;根据系统责任要求,找出对象的某些属性;考虑对象需要系统保存和管理的信息,找出对象的某些属性;对象需要在服务中实现其功能,需要增设一些属性;识别对象需要区别的状态,考虑是否需要增设一个属性来区别这些状态;确定属性表示整体和部分结构和实例连接。


软件体系结构

  1. 仓库或知识库结构:是一种以数据为中心的体系结构。包括两种不同的软件部件:一个中心数据库和一组相互独立的处理中心数据的子系统。主要适合数据由一个子系统产生而有其他子系统使用的场景。如:现代编译器

  1. 分层体系结构:层次化是一种概念,它将软件设计组织成为类或组件的层次或集合,在同一层次上的类或组件完成一个特定目的。良好的层次结构易于系统的扩展与维护,不同的层次之间通过接口进行通信。

  2. 模型/视图/控制器结构:视图是应用程序中用户界面相关的部分,即用户看到并与之交互的界面;控制器工作就是根据用户的输入,控制用户界面显示和更新模型对象的状态;模型是应用程序的主体部分,表示业务数据或业务逻辑。适合于交互式系统。

  3. 客户机/服务器结构:作为服务器的子系统为其他子系统的客户机提供服务;作为客户机的子系统负责和用户交互。分为瘦客户机模式和胖客户机模式。

    软件设计

    软件设计的原则:简单设计、灵活扩展、因地制宜、信息屏蔽、模块化、模块的独立性、启发式规则。

    软件设计的任务:系统体系结构、数据设计(数据结构的设计)、过程设计、界面设计。

    模块化:设计层次---软件系统、分解为子系统或包、分解为类、分解为子程序、子程序内部的设计;常见的子系统---业务规则、用户界面、数据库访问、对系统的依赖性;

    信息屏蔽:减少局部设计对全局的影响;强调通过接口进行通信;不鼓励使用全局变量;有助于实现封装;最终有利于实现软件的质量。

    模块独立:即功能独立。

    非直接耦合:如果两个模块中的每一个都能独立的工作而不需要另一个模块的存在,则称这两个模块是非直接耦合。

    数据耦合:模块之间只传递数据(程序中至少要存在数据耦合)。

    标记耦合:如果一组模块通过参数表传递记录数据,即这组模块共享这个记录。则称这组模块间是标记耦合。或者两个模块间传递的是数据结构,如数组名、记录名、文件名等这些名字即为标记,起始传递是这个数据结构的地址。

    控制耦合:模块之间除了传递数据,还有控制信息。如:一个模块通过传递开关、标志对另一个模块的多种功能进行选择,这两种模块间是控制耦合。

    外部耦合:一组模块都访问统一全局简单变量而不是同一数据结构。

    公共耦合:通过一个公共数据环境相互作用的那些模块间的耦合,公共数据环境可以是全程变量或者数据结构,公共的通信,内存的公共覆盖区及任意存储介质上的文件,物理设备等。BCE公共耦合。

内容耦合:当一个模块直接修改或操作另一个模块的数据,或者直接转入另一个模块时,就发生了内容耦合。此时,被修改的模块完全依赖于修改它的模块。如果发生下列情形,两个模块之间就发生了内容耦合

(1)一个模块直接访问另一个模块的内部数据;

(2)一个模块不通过正常入口转到另一模块内部;如goto语句

(3)两个模块有一部分程序代码重叠(只可能出现在汇编语言中)

(4)一个模块有多个入口。

耦合的使用原则:尽量使用数据耦合、少用控制耦合、限制公共耦合的范围、完全不用内容耦合

内聚:衡量模块内部各元素间结合的紧密程度。

偶然内聚:模块中的代码毫无关系。可能仅仅是因为多个地方重复出现为节约篇幅被凑成一个模块。各机能之间唯一的关系即是在同一模块中。

逻辑内聚:把逻辑上功能相似的数据和代码放在同一模块里。模块内执行模块相似的功能,通过参数确定该模块完成哪一个功能。(如鼠标和键盘)

时间内聚:同时要做的一些事情放到一个模块中,如初始化。

过程内聚:模块内的处理元素是相关的,并且依照固定顺序执行。

通信内聚:模块中所有元素都使用同一个输入数据或产生同一个输出。

顺序内聚:模块中一部分输出是另一部分的输入。

功能内聚:模块中各机能都对模块中单一明确定义的任务做贡献。

找出容易改变的区域:业务规则、对硬件的依赖性、输入和输出、非标准的语言特征和困难的设计区域。

设计模式

设计模式的组成:模式名称、问题、解决方案、效果。

  1. 适配器模式:目的---将一个类的接口转换成客户期望的另一种接口,是原来不匹配的接口而无法合作的类可以一起工作。

    类适配器:采用多重继承对一个接口与另一个接口匹配。

    对象适配器:依赖于对象组合。

  2. 组合设计模式(Composite模式):想表示对象的部分-整体的层次关系,典型的Composite对象结构是树形结构(递归组合);希望用户忽略组合对象和单个对象的不同。

  3. 观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知,并被自动更新。即主题对象发生改变,所依赖的观察者都得到通知,并更新。

    针对同一数据对象不同的表示形式

参与者职责
a)
主题( Subject):认得它的观察者。任意数目的观察者对象均可订阅一个主题。另外,提供一个连接观察者对象和解除连接的接口。
b)
观察者( Observer):定义了一个自我更新的接口。一旦发现主题有变时借助接口通知自己随之改变。
c)
具体主题( ConcreteSubject):存储具体观察者对象关心的状态;当状态改变时向它的观察者发送通知。

d) 具体观察者( ConcreteObserver):维持一个对具体主题对象的引用;存储要与主题一致的状态;实现观察者的自我更新接口,确保自己状态与主题的状态一致。

4、单例模式:它的核心结构中只包含一个被称为单例类的特殊类,一个类只有一个实例并提供一个访问它的全局访问点。该实例在系统生存期中都存在。

思路:通常,用户可以对应用系统进行配置,并将配置信息保存到配置文件中,应用系统在启动时首先将配置文件加载到内存中,这些内存配置信息应该有且仅有一份。

参与者职责:单件(Singleton)能够创建它唯一的实例;同时定义了一个Instance操作,允许外部存取它唯一的实例。Instance()是一个静态成员函数。(客户只能通过SingletonInstance()存取这唯一的实例)。

  1. 职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。这样的话学生需要与所有管理者之间发生耦合关系。

    适用性:有多个对象可以处理一个请求,哪个对象处理该请求运行是该自动确定;你想在不明确指定接收者的情况下,向多个对象中的一个提出请求;可处理一个请求的对象集合应被动态指定。

    实现:实现后继者链;实现后继者;表示请求。

  2. Factory模式(工厂模式):集中创建一组对象所需要的资源,(分离对象的使用和创建;创建一组派生类的对象)。

    简单工厂模式:不利于扩展,如增加ProductD需要修改Factory类的代码。

    工厂方法模式:适应于:需要扩展ProductD新建FactoryD类,对以前的没有影响,符合开放封闭原则。

    抽象工厂模式:

  3. Visitor模式(访问者模式):类层次与其操作分离。

    适应性:对象结构类有很多对象,但很少改变,而其上操作常改变(解耦数据结构和其上的操作);当该对象结构被很多应用共享时,访问者模式让每个应用仅包含需要的操作;想对对象结构中的对象进行不同且不相关的操作。N中元素—N个元素类,M个处理—MVisitor类。

    面向对象的设计

    OOA主要针对对象的问题域,识别有关的对象以及他们之间的关系,产生一个满足用户需求,独立于实现的OOA模型。

    OOD主要解决与实现有关的问题,基于OOA模型,针对具体的软硬件条件(如机器、网络、OSGUIDBMS等)产生一个可实现的OOD模型。

    问题域部分的设计:

    1)、为复用设计与编程的类而增加结构(目标:尽可能使复用成分增多,新开发的成分减少)。

    2)、提供性能:(把需要频繁交换信息的对象,尽量放在一台处理机上;增加属性或类,以保存中间结果;合并通讯频繁的类)。用聚合关系描述复杂类,为编程方便增加底层成分---细化对象的分类。

    3)、增加一般类以建立共同协议

    4)、按编程语言调整继承(把多继承调整为单继承:采用聚合、压平、不支持泛化)

    5)、调整与完善属性

    面向对象的设计原则:

    单一职责原则SRP:一个类只做一件事,只有一个原因可使其改变

    开放封闭原则OCP:所有原则的核心封装变化降低耦合;对扩展开放对修改封闭。

    依赖倒置原则DIP:依赖于抽象而不是依赖于实现。

    接口分离原则ISP:不强迫客户依赖它不需要的方法;一个接口只提供一个功能。

    里氏替换原则LSP:任何父类出现的地方都可以用它的子类替换,使用者无需了解两者之间的差异;

    优先使用组合原则CARP:优先使用组合而不是继承,有助于保持单一职责。

    软件测试

    单元测试环境:构造最小运行调度系统即驱动模块;模拟实现单元接口即桩模块;模拟生成测试数据和状态。

    驱动程序的作用:接受测试数据;调用被测模块,并把相关的测试数据传送给被测模块;获得测试结果。

    单元测试的内容:

    任务1:模块接口测试---检查模块接口是否正确(输入的形参和实参是否一致;调用其他模块的实参与被调模块的形参是否一致;全程变量在各模块中是否一致;外部输入、输出)。

    任务2:程序局部数据结构测试---检查局部数据结构的完整性(不适合不相容的数据结构;变量无初值;变量初始化或默认值有错;不正确的变量名或从未使用过;出现上溢或下溢和地址异常)。

    任务3:模块边界条件测试---检查临界数据处理的正确性(普通合法数据的处理;普通非法数据的处理;边界值内合法边界数据的处理;边界值外非法边界数据的处理)。

    任务4:模块独立执行通路测试---检查每条独立执行路径的测试,保证每条语句至少被执行一次(算符优先级;混合类型运算;精度不够;表达式符号;循环条件,死循环)。

    任务5:模块的各条错误处理通路测试---预见、预设的各种出错处理是否正确有效(输出的错误处理难以理解;记录的错误和实际不相符;程序定义的出错处理前系统已介入;异常处理不当;未提供足够的定位出错信息)。

    单元测试对象:JUnit

    JUnit体系结构

    使用Mock对象:

    使用Mock对象的步骤:使用一个接口来描述一个对象;为产品代码实现这个接口;如以测试为目的,在Mock类中实现这个接口。

    使用Mock对象的要求:可测试性设计---接口依赖

版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics