您的位置:首页 > 其它

软件工程,UML,开发模型和设计模式

2011-10-20 22:05 239 查看
周爱民,大道至简-软件工程实践者的思想,电子工业出版社

张逸,软件设计精要与模式,电子工业出版社

邱郁惠,C++程序员UML实务手册,机械工业出版社

★软件工程要点

软件工程层次模型EHM

软件设计分为两种:计划的设计与演进的设计。

架构设计需要重视的关注点有:程序组织、数据设计、安全性、性能、可扩展

性、可靠性、可用性。

实现团队经营
程序

(算法+结构)

过程

(RUP/XP)

组织

(管理/计划)

方法

(面向过程/OPP/MDA)

工程

(需求管理/工程管理/配置管理/文档化)

★UML

5类10图

用例图<不用于自动实现代码,主要用于组织相关的设计图文,如类图和序列图>

静态图(类图,对象图,包图)

行为图(状态图<一般不用于自动实现代码,而是用于分析得出类图和序列图>,活动图<即流程图,一般不用于自动实现代码>)

交互图(序列图,协作图<可以由UML工具根据序列图自动生成>)

实现图(构件图,配置图)

UML工具如StarUML和Rational Rose可以实现如下重要功能:正反向工程(根据类图输出源代码,或读取源代码反向输出类图),语法检验(不支持违反UML语法的绘图动作),支持XMI(支持XMI的输入导出,XMI是基于XML的交换格式),支持GoF设计模式。

1.用例图

小人:执行者。系统外部的一般用户(使用者或支持者),其可以是一个人,也可以是另一个相关的系统。

椭圆:用例。代表系统对外提供的一项服务。一个用例对应一个或多个序列图。

实线箭头:连接参与者和用例。由使用者指向用例或由用例指向支持者。

虚线箭头:标注<<include>>表示包含关系,由外部用例指向内部用例;标注<<extend>>表示扩展关系,由内部用例指向外部用例。

矩形方框:表示系统。系统的名字可以写在方框内部上方。

2.类图

矩形:类。内部通常划分为三部分:名称,属性,操作。{实现:+表示公有,-表示私有,#表示保护,斜体字表示抽象函数}

实线:关联。在实线的两端可以使用0..*形式来描述两个类在数量上的对应关系。也可以在一段或两端加上箭头表示导航性。{实现:箭头源端类中含有箭头指向端类的指针或指针数组}

实线菱形:在实现的一端加上空心/实心菱形表示聚合/组合,有菱形的一端是整体。一般空心表示整体聚合了部分的指针,而实心表示整体聚合了部分的实体。{实现:空心菱形实现也用指针;实心菱形的实现可以是在整体端类中含有部分端类的对象数组,也可以是整体端类中含有部分端类的指针,并提供创建部分端类的函数和在析构函数中释放指针数组的对象}

实线空心三角:泛化。描述类之间的继承关系,有三角一方是父类。{实现:继承}

虚线箭头:依赖。是一种动态关系,箭头指向的是被依赖的一方。{实现:依赖者的函数以被依赖者的对象为参数}

2-1.对象图

矩形:对象。内部通常分为两部分:对象名和数据值。格式分别为"对象名:类名","属性名=数据值"。其中对象名经常省略。

实线:关联。和相应类之间的关联是一致的。

2-2.包图

包图形:包。包图形是矩形左上方有一个小矩形。包是类的集合。

虚线箭头:依赖。如果两个包中的任意两个类之间存在依赖关系,则这两个包之间存在依赖关系。

3.状态图

圆角矩形:状态。

实心圆形:起点。

空心圆中有一个小实心圆:终点。

实线箭头:状态转移。状态的改变称作转移,箭头由旧状态指向新状态,箭头旁可以标出转移发生的条件。

3-1.活动图

圆角矩形:活动。

实心圆形:起点。

空心圆中有一个小实心圆:终点。

空心菱形:条件分支结构。

实线箭头:活动转移。当一个活动执行完毕之后,控制将沿着控制转移箭头转向下一个活动。箭头旁可以标出控制转移的条件。

4.序列图

小人:执行者。一般位于序列图最左端。

矩形:对象。每个对象分别带有一条虚线竖线,称作对象的生命线,它代表时间轴,时间沿竖线向下延伸。

实线箭头:消息。消息用从一条垂直的对象生命线指向另一个对象的生命线的水平箭头表示。一般由调用者指向被调用者。两个对象只有当所属类之间定义了关联、聚合、组合、或依赖关系时才能发送消息。{实现:执行者发送的消息对应main函数的一条调用,对象发送的消息对应所属类的函数中的一条调用;<<create>>表示调用构造函数,<<destroy>>表示调用析构函数}

4-1.协作图

矩形:对象。同对象图中的对象图符,通常简化为只有对象名。

实线:消息收发关系。实线旁边有一个箭头表示消息发送的方向,而消息名称前的序号表示消息执行的顺序。

5.构建图

构件图形:构件。构件图形是矩形左侧有两个小矩形。构件可以是源代码构件、二进制目标码构件、可执行构件或文档构件。

虚线箭头:依赖。

5-1.配置图

三维立方体:结点。结点表示实际的物理设备,如计算机和各种外部设备等。在结点里面,说明分配给该结点上运行的可执行构件或对象,从而说明哪些软件单元被分配在哪些结点上运行。

实线:连接关系。可以在实线旁说明连接方式。

★开发模型

1. 边做边改模型(Build-and-Fix Model)

  遗憾的是,许多产品都是使用"边做边改"模型来开发的。在这种模型中,既没有规格说明,也没有经过设计,软件随着客户的需要一次又一次地不断被修改.

其主要问题在于:

  (1) 缺少规划和设计环节,软件的结构随着不断的修改越来越糟,导致无法继续修改;

  (2) 忽略需求环节,给软件开发带来很大的风险;

  (3) 没有考虑测试和程序的可维护性,也没有任何文档,软件的维护十分困难。

2. 瀑布模型(Waterfall Model)

瀑布模型将软件生命周期划分为制定计划、需求分析、软件设计、程序编写、软件测试和运行维护等六个基本活动,并且规定了它们自上而下、相互衔接的固定次序,如同瀑布流水,逐级下落。

瀑布模型强调文档的作用,并要求每个阶段都要仔细验证。但是,这种模型的线性过程太理想化,已不再适合现代的软件开发模式,几乎被业界抛弃,其主要问题在于:

  (1) 各个阶段的划分完全固定,阶段之间产生大量的文档,极大地增加了工作量;

  (2) 由于开发模型是线性的,用户只有等到整个过程的末期才能见到开发成果,从而增加了开发的风险;

  (3) 早期的错误可能要等到开发后期的测试阶段才能发现,进而带来严重的后果。

3. 快速原型模型(RAPId Prototype Model)

  快速原型模型的第一步是建造一个快速原型,实现客户或未来的用户与系统的交互,用户或客户对原型进行评价,进一步细化待开发软件的需求。通过逐步调整原型使其满足客户的要求,开发人员可以确定客户的真正需求是什么;第二步则在第一步的基础上开发客户满意的软件产品。

4. 增量模型(Incremental Model)

  在使用增量模型时,第一个增量往往是实现基本需求的核心产品。核心产品交付用户使用后,经过评价形成下一个增量的开发计划,它包括对核心产品的修改和一些新功能的发布。这个过程在每个增量发布后不断重复,直到产生最终的完善产品。

  增量模型也存在以下缺陷:

  (1) 由于各个构件是逐渐并入已有的软件体系结构中的,所以加入构件必须不破坏已构造好的系统部分,这需要软件具备开放式的体系结构。

  (2) 在开发过程中,需求的变化是不可避免的。增量模型的灵活性可以使其适应这种变化的能力大大优于瀑布模型和快速原型模型,但也很容易退化为边做边改模型,从而使软件过程的控制失去整体性。

5.螺旋模型(Spiral Model)

  "螺旋模型",它将瀑布模型和快速原型模型结合起来,强调了其他模型所忽视的风险分析,特别适合于大型复杂的系统。

  螺旋模型沿着螺线进行若干次迭代,图中的四个象限代表了以下活动:

  (1) 制定计划:确定软件目标,选定实施方案,弄清项目开发的限制条件;

  (2) 风险分析:分析评估所选方案,考虑如何识别和消除风险;

  (3) 实施工程:实施软件开发和验证;

  (4) 客户评估:评价开发工作,提出修正建议,制定下一步计划。

  螺旋模型由风险驱动,强调可选方案和约束条件从而支持软件的重用,有助于将软件质量作为特殊目标融入产品开发之中。但是,螺旋模型也有一定的限制条件,具体如下:

  (1) 螺旋模型强调风险分析,但要求许多客户接受和相信这种分析,并做出相关反应是不容易的,因此,这种模型往往适应于内部的大规模软件开发。

  (2) 如果执行风险分析将大大影响项目的利润,那么进行风险分析毫无意义,因此,螺旋模型只适合于大规模软件项目。

  (3) 软件开发人员应该擅长寻找可能的风险,准确地分析风险,否则将会带来更大的风险

6.几种基本开发模型的比较

模型 优点 缺点

瀑布模型 文档驱动 系统可能不满足客户的需求

快速原型模型 关注满足客户需求 可能导致系统设计差、效率低,难于维护

增量模型 开发早期反馈及时,易于维护 需要开放式体系结构,可能会设计差、效率低

螺旋模型 风险驱动 风险分析人员需要有经验且经过充分训练

7.演化模型(incremental model)

  主要针对事先不能完整定义需求的软件开发。用户可以给出待开发系统的核心需求,并且当看到核心需求实现后,能够有效地提出反馈,以支持系统的最终设计和实现。软件开发人员根据用户的需求,首先开发核心系统。当该核心系统投入运行后,用户试用之,完成他们的工作,并提出精化系统、增强系统能力的需求。软件开发人员根据用户的反馈,实施开发的迭代过程。每一迭代过程均由需求、设计、编码、测试、集成等阶段组成,为整个系统增加一个可定义的、可管理的子集。 实际上,这个模型可看作是重复执行的多个“瀑布模型”。

8.喷泉模型(fountain model, (面向对象的生存期模型, OO模型))

喷泉模型与传统的结构化生存期比较,具有更多的增量和迭代性质,生存期的各个阶段可以相互重叠和多次反复,而且在项目的整个生存期中还可以嵌入子生存期。就像水喷上去又可以落下来,可以落在中间,也可以落在最底部。

9.eXtreme Programming(XP)

要求在开发过程中一直有客户的参与,被称为现场客户

很短的开发周期:任何一个开发分段都不超过3个星期

不会为了软件的扩展性而把目前不需要的功能加入到软件中来

使用重构(Refactoring)来进行渐进式设计

采用TDD和连续性整合

群体式负责制:任何人可以参与任何部分的开发

使用所谓的故事卡进行项目的计划规划

要求每周40小时工作时间

★设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。应用设计模式应该使得程序的结构更简单,而不是更复杂。评判复杂度的标准不是类的个数与代码量,而是看功能的实现方式是否能够消除重复代码,合理应对变化。

设计模式的精髓就在于封装变化,最大限度的保证软件的可扩展性。

设计模式的原则:

1."开-闭"原则

此原则是由"Bertrand Meyer"提出的。原文是:"Software entities should be open for extension,but closed for modification"。就是说模块应对扩展开放,而对修改关闭。模块应尽量在不修改原(是"原",指原来的代码)代码的情况下进行扩展。

2.里氏代换原则

里氏代换原则是由"Barbara Liskov"提出的。如果调用的是父类的话,那么换成子类也完全可以运行。可以说:里氏代换原则是继承复用的一个基础。

3.合成复用原则

就是说适当的时候,要少用继承,多用合成关系来实现。

4.依赖倒转原则

要针对接口编程,而不是针对实现编程。抽象不应该依赖于细节,细节应当依赖于抽象。传递参数,或者在组合聚合关系中,尽量引用层次高的类。

5.接口隔离原则

定制服务的例子,每一个接口应该是一种角色,不多不少,不干不该干的事,该干的事都要干。

6.抽象类

抽象类不会有实例,一般作为父类为子类继承,一般包含这个系的共同属性和方法。注意:好的继承关系中,只有叶节点是具体类,其他节点应该都是抽象类,也就是说具体类是不被继承的。将尽可能多的共同代码放到抽象类中。

7.迪米特法则

最少知识原则。不要和陌生人说话。

软件结构设计原则

1.抽象原则

抽象,是人们认识复杂事物的基本方法。它的实质是集中表现事物的主要特征和属性,隐蔽和忽略细节部分,并能用于概括普遍的、具有相同特征和属性的事物。

2.分而治之原则

将大的问题分为小的几部分问题,自上而下地分解策略,这是人们处理问题的通常的方式。

3.信息隐蔽的封装原则

隐藏各部分处理的复杂性,采用封装的方式,只留出简单的、统一形式的访问的方式。这样可以减少划分的各部分的依赖程度,增强可维护性。

4.模块化原则

模块,软件被划分成独立命名的,并可被独立访问的成分。模块划分,粒度可大可小。划分的依据是对应用逻辑结构的理解。

5.高内聚和低耦合原则

内聚性:软件成份的内部特性。耦合性:软件成份间关系的特性。

6.关注点分离原则

软件成份被用于不同的环境时,会有对于不同环境的适应性问题。但是,所必须适应的内容并非全部,只是一部分,即是所谓的关注点。

7.策略和实现分离原则

策略是软件中用于处理上下文相关的决策、信息语义和解释转换、参数选择等的成分。实现是软件中规范且完整的执行算法。

8.接口和实现分离原则

软件设计要将接口和实现分离,可保障成分的信息隐蔽性,以及提高维护性。

常见设计模式

Factory Method

将创建对象实例的责任转移到工厂类中,并利用抽象的原理,将实例化的行为延迟到具体工厂类。

技术要点:

1.将创建工厂对象的职责集中起来,放在一个模块中。绝不可以在需要创建产品时才创建工厂对象。

2.有利于类体系的建立,可以方便地对类体系增加新的派生类。

3.具体对象的解耦:(当对象实例的创建和某个关键字有关时)引入一个对象来保存关键字与工厂对象的映射关系,并提供一个注册方法来动态加入新的映射对。

Composite

它所要处理的是一种类似于递归组合的对象结构,可以使用树形图来描述,根结点是抽象类,枝节点是复合元素,叶节点是单元素。

技术要点:

1.透明模式:在根结点中声明所有用来管理子元素的方法,包括Add和Remove等。这样就完全消除了叶节点和枝节点对象在抽象层次的区别。缺点是由于模糊了枝节点和叶节点的区别而可能错误的调用叶节点的Add和Remove方法,不够安全。

2.安全模式:只在枝节点中声明管理子元素的方法。这导致了叶节点和枝节点接口的不完全一致,给调用带来了些微的不便。

3.改进:将管理子元素的方法封装到一个控制类中,这样是否能管理子元素就不是由继承层次决定,而是由如何实现这个控制类来决定。

Decorator

它可以动态的给对象添加一些额外的责任。

技术要点:

1.抽象修饰类应继承被修饰的类,同时聚合该类的实例对象。

2.既保留了采用聚合的优点:重用被修饰方法,避免被修饰类有自身继承体系时会出现类爆炸问题。

3.又保留了采用继承的优点:可以直接替换被修饰的类接口。

4.该模式可以方便的实现新增功能的组合。

Iterator

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

技术要点:

1.将遍历内部数据的方法进行抽象,就可以方便的支持新的遍历方法而且不会对需要遍历功能的其他类方法产生影响和增加对应新遍历方法的类方法。

2.类中其他方法需要遍历,也就是访问内部数据时,应该通过Iterator接口,绝不可以直接存取内部数据。

Strategy

Strategy模式就是一个“面向接口编程”原则的最佳体现,它进行抽象的一部分主要针对特定的“算法”,或者说是策略,通过引入Strategy模式,可以使算法或策略能够独立于调用它的客户而变化。

Adapter

Adapter模式的本意是“适配器”,作用是引入新的接口,使其与原有接口兼容。它通过引入的新接口来添加新的行为或属性。Decorator模式则是为原有行为“装饰”额外的职责,而不是为被装饰对象引入新的接口、新的行为。

技术要点:

1.类的Adapter模式只继承而不聚合被适配的类。优点是可以直接替换被适配的类接口,缺点是类爆炸问题。

2.对象的Adapter模式是将被适配的对象以聚合的方式放到适配的类中。优点是可以将被适配的类的子类直接初始化给适配的类,而不必为其引入新的适配类,从而没有类爆炸的问题。缺点是不可以替换被适配的类接口。

3.改进:对象的Adapter模式进行进一步的改进,使它继承被适配的类的抽象父类接口,从而克服它的固有缺陷。

Vistor

在已有的类体系的树形结构中,Vistor模式能够在不改变节点元素类的前提下,为各节点增加新的行为。它的最大特点是将被访问对象的行为与其依附的对象分离,并通过建立专门的Vistor对象来管理节点的行为。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: