系统架构设计师学习笔记 第八章 系统分析与设计方法

第八章 系统分析与设计方法

8.1 定义问题与归结模型

定义问题的过程包括:理解真实世界中的问题和用户的额需要,并提出满足这些需要的解决方案的过程。

8.1.1 问题分析

目标就是在开发之前对要解决的问题有一个更透彻的理解。为了达到这一目标,通常需要经过在问题定义上达成共识,理解问题的本质,确定项目干系人和用户,定义系统的边界和确定系统实现的约束这五个步骤。

1. 在问题定义上达成共识

应当将问题用标准的格式写出来,根据UP的建议,应当包括以下几个方面的要素。

  • 问题概述:用简短的几句话,将所理解的问题本质描述出来;
  • 影响:说明该问题将会对哪些项目干系人(风险承担者)产生影响;
  • 结果:确定问题对项目干系人和商业活动或产生什么样的影响;
  • 优点:概要性的提出解决方案,并列举出该解决方案的主要优点。

在问题定义上达成共识,能够有效的将开发团队的理解与用户的需求达成一致,这样就能够使得整个系统的开发沿着合理的方向发展。

2. 理解问题的本质

一种技术是“根本原因”分析,这是一种提示问题或其表象的根本原因的系统化方法。在实际的应用中,长使用因果鱼骨图和累托图两种方法。

因果鱼骨图

是一种有效的探寻问题根源的技术,它通过直观的图形找出问题或现象的所有潜在原因,从而追踪出问题的根源。提供了一种运用集体智慧解决问题的方法。在使用时,通常按照以下步骤进行。

  • 将问题简明扼要的写在右边的方框里;
  • 确定问题潜在原因的主要类别,把它们连到鱼的脊骨上;
  • 用头脑风暴方法寻找原因并归类。
帕累托法

是采用释放图的形式,根据问题的相对频率或大小从高往低将序排列,帮助设计师将精力集中在重要的问题上。它为80%的问题找到关键的20%的 原因,可以一目了然的显示出各个问题的相对重要程度,有助于预防在解决了一些问题后,却使另外一些问题变得更糟的现象发生。在使用时,通常按照以下步骤进行:

  • 明确问题:也就是前面达成共识的问题定义
  • 找出问题的各种可能原因
  • 选择评价标准和考察期限:最常用的评价标准包括频率(占总原因的百分比)和费用(产生的影响),而考察的期限则应具有相应问题的代表性,并不是越长越好。
  • 收集各种原因发生的频率及费用数据;
  • 将原因按照发生的频率或费用从大到小排列起来;
  • 将原因排在横轴上,频率或费用排列在纵轴上。

3. 确定项目干系人和用户

要想有效的解决问题,必须了解用户和其他相关的项目干系人(任何将从新系统或应用的实现中受到实质性影响的人)的需要。

4. 定义系统的边界

系统的边界是指解决方案系统和现实世界之间的边界。在系统边界中,信息以输入和输出的形式流入系统并由系统流向系统外的用户,所有和系统的交互都是通过系统和外部的接口进行的。在定义系统边界时,将世界分为两个部分:系统及与系统进行交互的事物。

要描述系统的边界有两种方法:一种是结构化分析中的“上下文范围图”,另一种则是面向对象分析中的“用例模型”。

  1. 上下文范围图。也就是数据流图中的顶层图,他是一个反映领域信息的模型,能够清晰的显示出系统的工作职责和相邻系统的职责起止支出,从而让读者能够从宏观的层面去了解系统。
  2. 用例模型。通过引入参与者来描述“和系统进行交互的事物”

然后,在根据每个参与者的功能需求,识别出代表系统功能的用例,从而界定系统的边界。

5. 确定系统实现的约束

由于各种因素的存在,会对解决方案的选择造成一定的限制,成这种限制为约束。每条约束都将影响到最后的解决方案的形成,甚至会影响是否能够提出解决方案。

8.1.2 问题定义

对于一个问题的完整定义,通常应包括目标、功能需求和非功能需求三个方面。

1. 目标

指构建系统的原因,他是最高层次的用户需求,是业务上的需要,而功能、性能需求则必须是以某种形式对该目标作出贡献。在描述目标时,应该注意一下几个方面。

  • 优势:目标应该不仅仅是解决问题,还要提供业务上的优势;
  • 度量:不仅要说明业务的优势,而且还必须提供度量这种优势的标准;
  • 合理性:要确保完成解决方案所需的工作量少于所获得的业务优势,这才是合理的解决方案;
  • 可行性:要探寻能够满足度量标准的解决方案;
  • 可达成性:对于组织而言,是否具备获取该系统的技能,构件完成狗是否能够操作它。

2. 功能需求

是用来指明系统必须做的事情,只有这些行为的存在,才有系统存在的价值。功能需求是在与用户或某个业务人员交谈时,他们所描述的内容是为了完成他们某部分的工作而必须做的事情。而在设计解决方案时,会遇到一些限制条件,这些东西也是“系统需求”的一部分,不过应该以设计约束或非功能需求形式指定。

需求的二义性主要体现在以下几个方面:

  1. 同名异义的词。
  2. 代词。

3. 非功能需求

是系统必备的属性,这些属性可以看做是一些使产品更有吸引力、易用、快速或可靠的特征或属性。非功能需求并不改变产品的功能,它是为工作赋予特征的。功能需求是以动词为特征的,而非功能需求则是以副词为特征的。非功能需求主要包括以下几种。

  1. 敏感需求:即产品外观的精神实质,也就是与用户界面的观感相关的一组属性。
  2. 易用性需求:也就是产品的易用程度,以及特殊的可用性考虑,通常包括用户的接受率、因为引入该产品而提高的生产效率、错误率、特殊人群的可用性等指标;
  3. 性能需求:也就是关于功能实现要求有多快、多可靠、多少处理量及多精确的约束。
  4. 可操作性需求:衡量产品的操作环境,以及对该操作环境必须考虑的问题;
  5. 可维护性和可移植性需求:期望的改变,以及完成改变允许的时间;
  6. 安全性需求:产品的安全保密性,通常体现为保密性、完整性和可获得性;
  7. 文化和政策需求:由产品的开发者和使用者所带来的特别需求;
  8. 法律需求:哪些法律和标准适用于本产品。

8.2 需求分析与软件设计

8.2.1 需求分析的任务与过程

需求分析主要就是确定待开发软件的功能、性能、数据、界面等要求。需求分析的实现步骤通常包括:获取当前系统的物理模型、抽象出当前系统的逻辑模型、建立目标系统的逻辑模型三个部分。具体来说,修分析阶段可以分成4个方面:

  1. 问题识别:用于发现需求、描述需求,以此来预先估计以后系统可能达到的目标。
  2. 分析与综合:对问题进行分析,然后在此基础上整合出解决方案。这个步骤是经常进行的,常用的方法有面向数据流的结构化分析方法,面向数据结构的Jackson方法,面向对象的分析方法以及用于建立动态模型的状态迁移图和Petri网。
  3. 编制需求分析的文档:也就是对已经确定的需求进行文档化描述,该文档通常称为“需求规格说明书”。
  4. 需求分析与评审:主要是对功能的正确性、完整性和清晰性,以及其它需求给予评价。

1. 需求的分类

  • 功能需求:指系统必须完成的,为了向它的用户提供有用的功能,产品必须执行的动作。
  • 非功能需求:指产品必须具备的属性或品质,如性能、响应时间、可靠性、容错性、扩展性等。
  • 设计约束:也称为限制条件、补充规约。

除了三种需求之外,还有业务需求、用户需求、系统需求这三个处于不同层面的概念

  • 业务需求:指反映组织结构或客户对系统、产品高层次的目标需求,通常问题定义本身就是业务需求。
  • 用户需求:指描述用户使用产品必须要完成什么任务,怎么完成的需求,通常是在问题定义的基础上进行用户访谈、调查,对用户使用的场景进行整理,从而建立从用户角度出发的需求。
  • 系统需求:是从系统的角度来说明软件的需求,它包括用特性说明的功能需求、质量属性、肺功能需求及设计约束。

2. 需求工程

就是包括创建和维护系统需求文档所必须的一切活动的过程,主要包括需求开发和需求管理两大工作。

  1. 需求开发:包括需求捕获、需求分析、编写规格说明书和需求验证4个阶段。在这个阶段需要完成确定产品所期望的用户类型,获取每种用户类型的需求,了解实际用户任务和目标这些任务所支持的业务需求、分析源于用户的信息、对需求进行优先级分类、将所收集的需求编写成为软件规格说明书和需求分析模型,对需求进行评审等工作。
  2. 需求管理:通常包括定义需求基线、处理需求变更、需求跟踪等方面的工作。

这两个方面是相辅相成的,需求开发是主线,是目标;需求管理是支持,是保障。换句话说,需求开发是努力更清晰,更明确的掌握客户对系统的需求;而需求管理管理则是对需求的变化进行管理的过程。

需求分析方法

  1. 结构化分析方法。
  2. 软系统方法
  3. 面向对象分析方法
  4. 面向问题域的分析PDOA

8.2.2 如果进行系统设计

优秀的系统设计一般在以下几个方面都很出色。

  1. 组件的独立性。审视自己设计的系统,是否做到了高内聚、低耦合?
  2. 例外的识别和处理。
  3. 防错和容错。

8.2.3 软件设计的任务与活动

软件设计是一个把软件需求变换成软件表示的过程,最初这种表示只是描绘出软件的总体框架,然后再进一步细化,并在此框架中填入细节。

1. 软件设计的两个阶段

  1. 概要设计。也称为高层设计,将软件需求转化为数据结构和软件的系统结构。例如,如果采用结构化设计,则将从宏观的角度讲软件划分成各个组成模块,病确定模块的功能及模块之间的调用关系。
  2. 详细设计。也称为低层设计,将对结构表示进行细化,得到详细的数据结构与算法。同样的,如果采用结构化设计,则详细设计的任务就是为每个模块进行设计。

2. 主要的设计方法比较

8.3 结构化分析与设计

8.3.1 结构化分析

结构化分析方法的基本思想是自顶向下逐层分解。分解和抽象是人们控制问题复杂性的两种基本手段。将一个大问题逐层逐级分解为最底层的问题,就是分解过程。

结构化分析与面向对象分析方法之间的最大差别是:结构化分析方法把系统看做一个过程的集合体,包括人完成的和电脑完成的;而面向对象方法则把系统看成一个相互影响的对象集。结构化分析方法的特点是利用数据流图来帮助人们理解问题,对问题进行分析。

结构化分析方法一般包括以下工具:数据流图DFD、数据字典DD、结构化语言、判定表、判定树。

结构化系统分析方法从总体上看是一种强烈依赖数据流图的自顶向下的建模方法。

1. 结构化分析的工作步骤

  1. 研究“物质环境”:首先,应画出当前系统(可能是非计算机系统,或是半计算机系统)的数据流图,说明系统的输入、输出数据流,说明系统的数据流情况,以及经历了哪些处理过程。这个过程可以帮助分析员有效的理解业务环境,在与用户的充分沟通与交流中完成。
  2. 建立系统逻辑模型。当物理模型建立之后,接下来的工作就是画出相对于真实系统的等价逻辑数据流图。在前一步骤建立的数据流图的基础上,将所有自然数据流都转成等价的逻辑流。
  3. 划清人机界限。最后,确定在系统逻辑模型中,哪些将采用自动化完成,哪些仍然保留手工操作。

2. 数据流图

DFD是一种图形化的系统模型,它在一张图中展示信息系统的主要需求,即输入、输出、处理(过程)、数据存储。DFD包括以下几个基本元素

  • 过程:也称为加工,一步步的执行指令,完成输入到输出的转换。
  • 外部实体:也称为源/宿,系统之外的数据源或目的。
  • 数据存储:也称为文件,存放数据的地方,一般是以文件、数据库等形式出现。
  • 数据流:从一处到另一处的数据流向,数从数据或数据到一个过程的数据流。
  • 实时连接:当过程执行时,外部实体与过程之间的来回通信。
  1. 数据流图的层次。数据流图提供一种表现系统高层和低层概念的机制,也就是先绘制一张较高层次的数据流图,然后再次基础上,对其中过程(处理)进行分解,分解成为若干独立的、低层次的、详细的数据流图,而且可以这样逐一分解下去,知道系统被清晰的描述出来。
  2. Context图。也就是系统上下文范围关系图。这是描绘系统最高层结构的DFD图。它的特点是:将整个待开发的系统表示为一个过程,将所有的外部实体和进出系统的数据流都画在一张图中。用来描述系统有什么输入、输出数据流,与哪些外部实体直接相关,可以把整个系统的范围勾画出来。
  3. 逐级分解。当完成了Context图的建模之后,就可以在此基础上进行进一步的分解。
  4. 如何画DFD。DFD的绘制是一个自顶向下、由外到里的过程,通常按照以下几个步骤进行。
  • 画系统的输入和输出:就是在图的边缘标出系统的输入、输出数据流。这一步其实是绝地你个研究的内容和系统的范围。在画的时候,可以先将尽可能多的输入、输出画出来,然后再删除多余的,增加遗漏的。
  • 画数据流图的内部:将系统的书、输出用一系列的处理连接起来,可以从输入数据流花香输出数据流,也可以从中间画出去。
  • 为每一个数据流命名:命名的好坏与数据流图的可理解性密切相关,应避免使用空洞的名字。
  • 为加工命名:注意应使用动宾短语。
  • 不考虑初始化也重点,暂不考虑出错路径等细节,不画控制流和控制信息。

3. 细化记录DFD部件

为了更好的描述DFD的部件,结构化分析方法还引入了数据字典、结构化语言及决策树、决策表等方法。其中数据字典应用最为广泛。

数据字典技术是一种很实用、有效的表达数据格式的手段。他是对所有与系统相关的数据元素的一个有组织的列表和精确严格的定义。使得用户和系统分析员对于输入、输出、存储层粉和中间计算机有共同的理解。通常数据字典的每一个条目中包括以下信息。

  1. 名称:数据或控制箱、数据存储或外部实体的主要名称,如果有别名的还应该将别名列出来。
  2. 何处使用/如何使用
  3. 内容描述:说明该条目的内容组成,通常采用以下符号进行说明
  • =:由...构成
  • +:和,代表顺序连接的关系。
  • [|]:或,代表从中选一个
  • {}*:n次重复
  • ():代表可选的数据项
  • *...*:表示特定限制的注释
  1. 补充信息:关于数据类型、默认值、限制等信息。

8.3.2 结构化设计

结构化设计包括架构设计、接口设计、数据设计和过程设计等任务。他是一种面向数据流的设计方法,是以结构化分析阶段所产生的成果为基础,进一步自顶向下、逐步求精和模块化的过程。

1. 概要设计与详细设计的主要任务

概要设计阶段的主要任务是设计软件的结构、确定系统是由哪些模块组成,以及每个模块之间的关系。它采用结构图来描述程序的结构,此外还可以使用层次图和HIPO(层次图加输入/处理/输出图)。

整个过程主要包括:复查基本系统模型、复查并精化数据流图、确定数据流图的信息流类型(包括交换流和事务流)、根据流类型分别实施变换分析或事务分析、根据软件设计原则对得到的软件结构图进一步优化。

而详细设计阶段的主要任务则是确定应该如何具体的实现所要求的系统,得出对目标系统的精确描述。它采用自顶向下、逐步求精的设计方式和单入口单出口的控制结构。

2. 结构图

结构图的基本成分包括模块、调用(模块之间的调用关系)和数据(模块间传递及处理数据信息)。

结构图是在需求分析阶段产生的数据流图的基础上进行进一步的设计。它将DFD图中的信息流分为两种类型。

  • 交换流:信息首先沿着输入通路进入系统,并将其转换为内部表示,然后通过变换中心(加工)的处理,再沿着输出转换为外部形式离开系统。具有这种特性的加工流就是交换流。
  • 事务流:信息首先沿着输入通路进入系统,事务中心根据输入信息的类型在若干个动作序列(活动流)中选择一个执行,这种信息流称为事务流。

3. 程序流程图和盒图

程序流程图和盒图都是用来描述程序的细节逻辑的。

程序流程图的特点是简单、直观、易学,但它的缺点是由于其随意性而使得画出来的流程图容易成为非结构化的流程图。

盒图的主要特点是功能域明确、无法任意转移控制、容易确定全局数据和局部数据的作用域、容易表示嵌套关系、可以表示模块的层次结构。但它的缺点是修改相对比较困难。

4. PAD和PDL

PAD是问题分析图的缩写,它符合自顶向下、逐步求精的原则,也符合结构化程序设计的思想,最大的特点在于能够很方便的转换为程序语言的源程序代码。

PDL这是语言描述工具的缩写,它和高级程序语言很相似,也包括数据说明部分和过程部分,还可以带注释等成分,但它是不可执行的。PDL是一种形式化语言,其控制结构的描述是确定的,但内部的描述语法是不确定的。PDL通常也被称为伪码。

8.3.3 模块设计

模块是执行某一特定任务的数据结构和程序代码。通常将模块的接口和功能定义为其外部特性,将模块的局部数据和实现该模块的程序代码称为内部特性。而在模块设计中,最重要的原则就是实现信息隐蔽和模块独立。

1. 信息隐蔽原则

信息隐蔽是开发整体程序结构时使用的法则,即将每个程序的成分隐藏或封装在一个单一的设计模式中,并且尽可能少的暴露其内部的处理。通常将难的决策、可能修改的决策、数据结构的内部连接以及对它所做的操作细节、内部特征码、与计算机硬件有关的细节等隐蔽起来。

通过信息隐蔽可以提高软件的可修改性、可测试性和可移植性。

2. 模块独立性原则

模块独立是指每个模块完成一个相对独立的特定子功能,并且与其他模块之间的联系最简单。保持模块的高度独立性,也是设计过程中的一个很重要的原则。通常用耦合(模块之间联系的紧密程度)和内聚(模块内部各元素之间联系的紧密程度)两个标准来衡量,设计的目标是高内聚、低耦合。

模块的内聚类型如下图,根据内聚度从高到低排序

内聚类型 描述
功能内聚 完成一个单一功能,各个部分协同工作,缺一不可
顺序内聚 处理元素相关,而且必须顺序执行
通信内聚 所有处理元素集中在一个数据结构的区域上
过程内聚 处理元素相关,并且必须按特定的次序执行
瞬时内聚 所包含的任务必须在同一时间间隔内执行(如初始化模块)
逻辑内聚 完成逻辑上相关的一组任务
偶然内聚 完成一组没有关系或松散关系的任务

模块的耦合类型如下图,根据耦合度从低到高排序

耦合类型 描述
非直接耦合 没有直接联系,互相不依赖对方
数据耦合 借助参数表传递简单数据
标记耦合 一个数据结构的一部分借助于模块接口来传递
控制耦合 模块间传递的信息中包含用于控制模块内部逻辑的信息
外部耦合 与软件以外的环境有关
公共耦合 多个模块引用同一个全局数据区
内容耦合 一个模块访问另外一个模块的内部数据<br />一个模块不通过正常入口转入到另一个模块的内部<br />两个模块有一部分程序代码重叠<br />一个模块有多个入口

除了满足以上两大基本原则外,通常在模块分解时还需要注意:保持模块的大小适中,尽可能减少调用的深度,直接调用该模块的个数应该尽量大,但调用其他模块的个数则不宜过大;保证模块是单入口、单出口的;模块的作用域应该在控制域之内;功能应该是可预测的。

8.4 面向对象的分析与设计

8.4.1 面向对象的基本概念

1. 对象和类

对象是系统中用来描述客观事物的一个实体,它由对象标识(名称)、属性(状态、数据、成员变量)和服务(操作、行为、方法)三个要素组成,它们被封装为一个整体,以接口的形式对外提供服务。

类是对具有相同属性和服务的一个或一组对象的抽象。类与对象是抽象描述和具体实例的关系,一个具体的对象被称为类的一个实例。

在系统设计过程中,类可以分为三种类型,分别是实体类、边界类和控制类。

  1. 实体类:实体类映射需求中的每个实体,实体类保存需要存储在永久存储体重的信息。实体类通常是永久性的,它们所具有的属性和关系是长期需要的,有时甚至在系统的整个生存周期都需要。
    实体类通常采用业务领域术语命名,一般来说是一个名词,在用例模型向领域模型的转化中,一个参与者一般对应于实体类。通常可以从SRS中的那些与数据库表(需要持久存储)对应的名词着手来寻找实体类。通常情况下,实体类一定有属性,但不一定有操作。
  2. 控制类:控制类是用于控制用例工作的类,一般是由动宾结构的短语(“动词+名词”或“名词+动词”)转化来的名词。控制类用于对一个或几个用例所特有的控制行为进行建模,控制对象(控制类的实例)通常控制其他对象,因此,它们的行为具有协调性。
    通常情况下,控制类没有属性,但一定有方法
  3. 边界类:用于封装在用例内、外流动的信息或数据流。边界类位于系统与边界的交界处,包括所有窗体、报表、打印机和扫描仪等硬件的接口,以及与其他系统的接口。每个参与者与用例交互至少要有一个边界类。
    边界类用于系统接口与系统外部进行交互,边界对象将系统与其外部环境的变更分隔开,使这些变更不会对系统的其他部分造成影响。通常情况下,边界类可以既有属性也有方法。

2. 继承与泛化

继承用来说明特殊类(子类)与一般类(父类)的关系,而通常用泛化来说明一般类和特殊类的关系,也就是说它们是一对多关系。

3. 多态与重载

多态性(即多种形式)一般是指一般类中定义的属性被特殊类继承后,可以具有不同的数据类型或表现出不同的行为,通常是使用重载和改写两项技术来实现的

多态类型 描述
重载(专用多态) 描述一个函数名称有多种不同实现方式,通常可以在编译时基于类型签名来区分各个重载函数的名称
改写(包括多态) 是重载的一种特殊情况,只发生在有关父类和子类之间关系中。通常签名相同,内容不一样。
多态变量(赋值多态强制多态) 声明为一种类型,但实际上却可以包含另一种类型数值的变量
泛型(模板,参数多态) 它提供了一种创建通用工具的方法,可以在特定的场合将其特化

重载是编译时进行的(静态绑定),而改写则是运行时选择的(动态绑定)。

4. 模板类

也称类属类,用来实现参数多态机制。一个类属类是关于一组类的特性抽象,强调的是这些类的成员特征中与具体类型无关的那些部分,而用变元来表示与具体类型有关的那些部分。

5. 消息和消息通信

消息就是向对象发出的服务请求,通常包括提供服务的对象标识、消息名、输入信息和回答消息。消息通信则是面向对象方法学中的一个重要原则,它与对象的封装原则密不可分,为对象间提供了唯一合法的动态联系的途径。

8.4.2 面向对象分析

1. OOA/OOD方法

OOA模型中包括主题、对象类、结构、属性和服务5个层次,需经过标识对象类、标识结构与关联、划分主题、定义属性、定义服务5个步骤来完成整个分析同坐。

OOD中将贯穿OOA中的5个层次和5个活动,它由人机交互部件、问题域部件、任务管理部件、数据管理部件4个部分组成,其主要的活动就是这4个部件的设计工作。

  • 设计问题域部分:OOA的结果恰好是OOD的问题域部件,分析的结果在OOD中可以被改动或增补,但基于问题域的总体组织框架是长时间稳定的;
  • 设计人机交互部件:人机交互部件在上述结果中加入人机交互的设计和交互的细节,包括窗口和输出服务的设计。可以用原型来帮助实际交互机制进行开发和选择;
  • 设计任务管理部分:这部分主要是识别事件驱动任务,识别时钟驱动任务,识别优先任务和关键任务,识别协调者,审查每个任务并定义每个任务。
  • 设计数据管理部分:数据管理部分提供了在数据管理系统中存储和检索对象的基本结构,其目的是隔离数据管理方法对其他部分的影响。

2. Booth方法

Booth任务软件开发是一个螺旋上升的过程,每个周期中包括标识类和对象、确定类和对象的含义、标识关系、说明每个类的接口和实现四个步骤。

/ 静态模型 动态模型
逻辑模型 类图<br />对象图 状态转换图<br />时序图
物理模型 模块图<br />进程图

Booth方法的挨罚过程是一个迭代的、渐进式的系统开发过程,它可以分为宏过程和微过程两类。宏过程用于控制微过程,是覆盖几个月或几周所进行的活动。它包括负责建立核心需求的概念化,为所期望的行为建立模型的分析,建立架构的设计,形成实现的进化,以及管理软件交付使用的维护等5个主要活动。

而微过程则基本上代表了开发人员的日常活动,它由4个重要、没有顺序关系的步骤组成:在给定的抽象层次上识别出类和对象,识别出这些类和对象的语义,识别出类间和对详见的关系,实现类和对象。

3. OMT方法

OMT是对象建模技术的缩写,主要用于分析、系统设计和对象设计。包括对象模型(静态的、结构化的系统的“数据”性质,通常采用类图)、动态模型(瞬时的、行为化的系统“控制”性质,通常使用状态图)和功能模型(表示变化的系统的“功能”性质,通常使用数据流图)。OMT方法的三大模型如下表

模型 说明 主要技术
对象模型 描述系统中对象的静态结构、对象之间的关系、属性、操作。它表示静态的、结构上的、系统的“数据”特征 对象图
动态模型 描述与时间和操作顺序有关的系统特征,如激发事件、事件序列、确定事件先后关系的状态。它表示瞬时、行为上的、系统的“控制”特征 状态图
功能模型 描述与值的变换有关的系统特征:功能、映射、约束和函数依赖 数据流图

4. OOSE方法

面向对象软件工程的缩写。它在OMT的基础上,对功能模型进行了补充,提出了“用例”的概念,最终取代数据流图进行需求分析和建立功能模型。

8.4.3 统一建模语言

1. UML是什么

  • UML是一种语言。为软件开发人员之间提供给了一种用于交流的词汇表和一种用于软件蓝图的标准语言。
  • UML是一种可视化语言
  • UML是一种可用于详细描述的语言:UML所建的模型是精确的、无歧义和完整的,因此适合于对所有重要的分析、设计和实现决策进行详细描述。
  • UML是一种构造语言
  • UML是一种文档化语言:适合于建立系统架构及其所有的细节文档。

2. UML的结构

UML由构造快、公共机制和架构三个部分组成。

  1. 构造块。构造块也就是基本的UML建模元素(事物)、关系和图。
  • 建模元素:包括结构事物(类、接口、协作、用例、活动类、组件、节点等)、行为事物(交互、状态机)、分组事物(包)、注释事物。
  • 关系:包括关联关系、依赖关系、泛化关系、实现关系。
  • 图:UML2.0包括14中不同的图,分为表示系统静态结构的静态模型(包括类图、对象图、包图、构件图、部署图、制品图),以及表示系统动态结构的动态模型(包括对象图、用例图、顺序图、通信图、定时图、状态图、活动图、交互概览图)。
  1. 公共机制。指达到特定目标的公共UML方法。
  • 规格说明:规格说明是元素语义的文本描述,它是模型的重要组成部分。
  • 修饰:UML为每一个模型元素设置了一个简单的记号,还可以通过修饰来表达更多的信息。
  • 公共分类:包括类元与实体(类元表示概念,而实体表示具体的实体)、接口和实现(接口用来定义契约,而实现就是具体的内容)两组公共分类。
  • 扩展机制:包括约束(添加新规则来扩展元素的语义)、构造型(用于定义新的UML建模元素)、标记值(添加新的特殊信息来扩展模型元素的规格说明)。
  1. 架构。UML对系统架构的定义是:系统的组织结构,包括系统分解的组成部分、它们的关联性、交互、机制和指导原则,这些提供系统设计的信息。而具体来说,就是指5个系统视图。
  • 逻辑视图:以问题域的词汇组成的类和对象集合。
  • 进程视图:可执行县城和进程作为活动类的建模,它是逻辑视图的一次执行实例。
  • 实现视图:对组成基于系统的物理代码的文件和组件进行建模
  • 部署视图:把组件物理的部署到一组物理的、可计算的节点上。
  • 用例视图:最基本的需求分析模型

3. 用例图基础

用例实例实在系统中执行的一系列动作,这些动作将生成特定参与者可见的价值结果。一个用例定义一组用例实例。

用例模型描述的是外部参与者所理解的系统功能。用例模型用于需求分析阶段,它的建立是系统开发者和用户反复讨论的结果,表明了开发者和用户对需求规格达成的共识。

  1. 参与者。参与者代表与系统接口的任何事物或人,是指代表某一种特定功能的角色。因此,参与者都是虚拟的概念。在UML中,用一个小人表示参与者
  2. 用例。用例是对系统行为的动态描述,它可以促进设计人员、开发人员与用户的沟通,理解正确的需求、还可以划分系统和外部实体的界限,是系统设计的起点。
  3. 包含和扩展。两个用例之间的关系可以主要概况为两种情况。一种是用于重用的包含关系,用构造型<<include>>或者<<use>>表示;另一种是用于分离出不同的行为,用构造型<<extend>>表示。
  • 包含关系:当可以从两个或两个以上的原始用例中提取公共行为,或者发现能够使用一个组件来实现某一个用例的部分功能是很重要的事时,应该使用包含关系来表示。所提取出来的公共行为称为抽象用例。
  • 扩展关系:如果一个用例明显的混合了两种或两种以上的不同场景,即根据情况可能发生多种事情。可以将这个用例分为一个主用例和一个或多个辅用例,描述可能更加清晰。

4. 类图和对象图基础

在面向对象建模技术中,将客观世界的实体映射为对象,并归纳成一个个类。类、对象和它们之间的关联是面向对象技术中最基本的元素。对于一个想要描述的系统,其类型和对象模型揭示了系统的结构。在UML中,类和对象模型分别由类图和对象图表示。类图是OO方法的核心。

  1. 类和对象。通常用对象描述客观世界中某个具体的实体。类是对一类具有相同特征的对象的描述。对象是类的实例。在UML中,类的可视化表示为一个划分成三个格子的长方形(下面两个格子可省略)。
  • 类的获取和命名:最顶部的格子包含类的名称。
  • 类的属性:中间的格子包含类的属性,用以描述该类对象的共同特点。该项可省略。UML规定类的属性的语法为:“可见性 属性名:类型 = 默认值 {约束特性}”。
    可见性包括Public、Private和Protected,分别用+、-、#表示。
    类型表示该类的种类,它可以是基本数据类型,例如整数、实数、布尔型等,也可以使用户自定义的类型。一般它由所涉及的程序设计语言确定。
    约束特性则是用户对该属性性质的一个约束说明。例如“{只读}”说明该属性是只读属性。
  • 类的操作:该项可省略。操作用于修改、检索类的属性或执行某些动作。操作通常也被称为功能,但是它们被约束在类的内部,只能作用到该类的对象上。操作名、返回类型和参数表组成操作界面。UML规定操作的语法为“可见性:操作名(参数表):返回类型 {约束特性}”。
    类图描述了类和类之间的静态关系。
  1. 类之间的关系。关系是事物间的连接,在面向对象建模中,有4个很重要的关系。
  • 依赖关系。有两个元素X、Y,如果修改元素X的定义可能会引起对另一个元素Y的定义的修改,则称元素Y依赖于元素X。在UML中,使用带箭头的虚线表示依赖关系。
  • 泛化关系。描述了一般事物与该事物中的特殊种类之间的关系,也就是父类与子类之间的关系。继承关系是泛化关系的反关系。也就是说子类是从父类中集成的,而父类则是子类的泛化。在UML中,使用带空心箭头的实线表示,箭头指向父类。
    在UML中,对泛化关系有三个要求:
    a. 子类应与父类完全一致,父类所具有的关联、属性和操作,子类都应具有。
    b. 子类中除了与父类一致的信息外,还包括额外的信息。
    c. 可以使用父类实例的地方,也可以使用子类实例。
  • 关联关系。关联表示两个类之间存在某种语义上的联系。在UML中,用一条实线来表示关联关系。
    a. 聚合关系:聚合表示类之间的关系是整体和部分的关系。在UML中,用一个带空心菱形的实线表示,空心菱形指的是代表“整体”的类。
    b. 组合关系:如果聚合关系中的表示“部分”的类存在,与表示“整体”的类有着紧密的关系,那么就应该使用“组合”关系来表示。在UML中,用带有实心菱形的实线表示,菱形指向的是代表“整体”的类。
  • 实现关系。是用来规定接口和实现接口的类或组件之间的关系的。接口是操作的集合,这些操作用于规定类或组件的服务。在UML中,用一个带空心箭头的虚线表示。
  1. 多重性问题:重复性又称多重性,多重性表示为一个整数范围n...m,整数n定义所连接的最少对象的数目,而m则为最多对象数(当不知道确切的最大数时,最大数用表示)。最常见的多重性有:0...1;0...;1...1;1...;
    多重性是用来说明关联的两个类之间的数量关系的。
  2. 类图。对于软件系统,其类模型和对象模型类图描述类和类之间的静态关系。与数据模型不同,它不仅显示了信息的结构,同时还描述了系统的行为。类图是定义其他图的基础。
  3. 对象图。UML中对象图与类图有相同的表示形式。对象图可以看做是类图的一个实例。对象是类的实例;对象之间的链是类之间的关联的实例。对象与类的图形表示相似,均为划分成两个格子的长方形(下面的格子可省略)。上面的格子是对象名,对象名下有下划线;下面的格子记录属性值。链的图形表示与关联相似。对象图常用于表示复杂类图的一个实例。

5. 交互图基础

交互图是表示各组对象如何依赖某种行为进行写作的模型。通常可以使用一个交互图来表示和说明一个用例的行为。

  1. 顺序图。用来描述对象之间动态的交互欢喜,着重体现对象间消息传递的时间顺序。顺序图允许直观的表示出对象的生存期,在生存期内,对象可以对输入消息作出响应,并且可以发送信息。
    对象间的通信通过在对象的生命线上画消息来表示。消息的箭头知名消息的类型。顺序图中的消息可以使信号、操作调用或类似于C++中的RPC和JAVA中的RMI。当收到消息时,接收对象立即开始执行活动,即对象被激活了。通过在对象生命线上显示一个细长矩形框来表示激活。
    消息可以用消息名及参数来标识,消息也可带有顺序号。消息还可以带有条件表达式,表示分支或决定是否发送消息。如果用于表示分支,则两个分支是相互排斥的,即在某一时刻仅可发送分支中的一个消息。
  2. 通信图。用于描述相互合作的对象间的交互关系和链接关系。顺序图着重体现交互的时间顺序,通信图则着重体现交互对象间的静态链接关系。
  3. 定时图。着重表示定时约束的定时图。
    根据UML的定义,定时图实际上是一种特殊形式的顺序图,它与顺序图的区别主要在几个方面:
  • 坐标轴交换了位置,改为从左到右来表示时间的推移。
  • 用生命线的“凹下凸起”来表示状态的变化,每个水平位置代表一种不同的状态,状态的顺序可以有意义、也可以没有意义。
  • 生命线可以跟在一根线后面,在这根线上显示一些不同的状态值。
  • 可以显示一个度量时间值得标尺,用刻度表示时间间隔。
    定时图的土元包括生命线、状态、状态变迁、消息、时间刻度。

6. 状态图基础

用来描述一个特定对象的所有可能状态及其引起状态转移的事件。一个状态图包括一系列状态及状态之间的转移。

状态图包括以下部分:

  • 状态:又称为中间状态,用圆角矩形框表示
  • 初始状态:又称为初态,用一个黑色的实心圆圈表示,在一张状态图中只能够有一个初始状态。
  • 结束状态:又称为终态,在黑色的实心圆圈外面套上一个空心圆,在一张状态图中可能有多个结束状态。
  • 状态转移:用箭头说明状态的转移情况,并用文字说明引发这个状态变化的相应事件是什么。

一个状态也可能被细分成为多个子状态,那么如果将这些子状态都描绘出来的话,那么这个状态就是符合状态。

7. 活动图基础

活动图是由状态图变化而来的。活动图依据对象状态的变化来捕获动作(将要执行的工作或活动)与动作的结果。活动图中一个活动结束后将立即进入下一个活动(在状态图中状态的变迁可能需要事件的触发)。

  1. 基本活动图。活动图与状态图类似,包括了初始状态、终止状态,以及中间的活动状态,每个活动之间也就是一种状态的变迁。在活动图中,还引入了以下几个概念:
  • 判定:说明基于某些表达式的选择性路径,在UML中用菱形表示。
  • 分支与组合:处理并发流,UML中使用粗线表示。
  1. 带泳道的活动图。将活动图的逻辑描述与顺序图、协作图的责任描述结合起来。
  2. 对象流:在活动图中可以出现对象。对象可以作为活动的输入或输出,对象与活动间的输入/输出关系用虚线箭头来表示。如果仅表示对象受到某一活动的影响,则可用不带箭头的虚线来连接对象与活动。
  3. 信号:在活动途中可以表示信号的发送与接收,分别用发送与接收标识来表示。发送和接收标识也可与对象相连,用于表示消息的发送者和接收者。

8. 构件图基础

构件图是面向对象系统的物理方面进行建模要用的两种图之一。它可以有效的显示一组构件,以及他们之间的关系。构件图中通常包括构件、接口及各种关系。

通常构件值得是源代码文件、二进制代码文件和可执行文件等。而构件图就是用来显示编译、链接或执行时构件之间的依赖关系的。通常来说,可以使用构件图完成以下工作:

  • 对源代码进行建模:这样可以清晰地表示出各个不同源程序文件之间的关系。
  • 对可执行体的发布建模:将清晰地表示出各个可执行文件、DLL文件之间的关系。
  • 对物理数据库建模:用来表示各种类型的数据库、表之间的关系。
  • 对可调整的系统建模

在绘制构件图时,应该注意侧重于描述系统的静态实现视图的一个方面,图形不要过于简化,应该为构件图取一个直观的名称,在绘制时避免产生线的交叉。

9. 部署图基础

也成为实施图,和构件图一眼个,是面向对象系统的物理方面建模的两种图之一。构件图说明构建之间的逻辑关系,而部署图是在此基础上更进一步的描述系统硬件的物理拓扑结构及在此结构上运行的软件构件,常用于帮助理解分布式系统。通常包括以下一些关键的组成部分:

  1. 节点和连接。节点代表一个物理设备及其上运行的软件系统。在UML中,使用一个立方体表示一个节点,节点名放在左上角。节点之间的连线表示系统之间进行交互的通信路径,在UML中被称为连接。通信类型则放在连接旁边的“《》”之间,表示所用的通信协议或网络类型
  2. 构件和接口。在部署图中,构件代表可执行的物理代码模块,如一个可执行程序。
    在面向对象方法中,类和构件等元素并不是所有的属性和操作都对外可见。他们对外提供了可见操作和属性,称之为类和构件的接口。界面可以表示为一头是一个小圆圈的直线。

8.5 用户界面设计

接口设计主要包括三个方面的内容:一是设计软件构件间的接口;二是软件设计模块和其他非人的信息生产者和消费者(如外部实体)的接口;三是人(如用户)和计算机间的界面设计。

8.5.1 用户界面设计的原则

设计时必须遵从三个黄金法则

  • 置用户与控制之下:具体来说就是以不强迫用户进入不必要的或不希望的动作的方式来定义交互模式、提供灵活的交互、允许用户交互时可以被中断和撤销、当技能级别增长时可以使交互流水化并允许定制交互、使用户隔离内部细节、设计应允许用户和出现在屏幕上的对象直接交互。
  • 减少用户的记忆负担:具体来说就是减少对短期记忆的要求、建立有意义的默认、定义直觉性的捷径、界面的视觉布局应该基于对真实世界的隐喻、以不断进展的方式提示信息。
  • 保持界面的一致性:具体来说就是允许用户将当前任务放入有意义的语境、在应用系列内保持一致性,如果过去的交互模型已经建立了用户期望,除非有不得已的理由,否则不要改变它。

用户界面设计原则如下:

原则 描述
用户熟悉 界面所使用的术语和概念应该来自于用户的经验,这些用户是将来要使用系统最多的人。
意外最小化 永远不要让用户对系统的行为感到吃惊。
可恢复性 界面应该有一种机制来允许用户从错误中恢复
用户指南 在错误发生时,界面应该提供有意义的反馈,并有上下文感知能力的用户帮助功能。
用户差异性 界面应该为不同类型用户提供合适的交互功能

8.5.2 用户界面设计过程

用户界面的设计过程也应该是迭代的,它通常包括4个不同的框架活动:

  1. 用户、任务和环境分析:着重于分析将和系统交互的用户的特点,记录下技术级别、业务理解和对新系统的一般感悟,并定义不同的用户类别。然后对用户将要完成什么样的任务进行详细的标识和描述。最后对用户的物理工作环境进行了解和分析。
  2. 界面设计:主要包括建立任务的目标和意图,为每个目标或意图定制特定的动作序列,按在界面上执行的方式对动作序列进行规约,指明系统状态,定义控制机制,指明控制机制如何影响系统状态,指明用户如何通过界面上的信息来解释系统状态。
  3. 实现:就是根据界面设计进行实现,前期可以通过原型工具来快速实现,减少返工的工作量。
  4. 界面确认:界面实现后就可以进行一些定性和定量的数据收集,以进行界面的评估,以调整界面的设计。

8.6 工作流设计

8.6.1 工作流设计概述

工作流是一类能够完全或者部分自动执行的经营过程,根据一系列过程规则、文档、信息或任务在不同的执行者之间传递、执行。

  1. 工作流。是现实中的具体工作从开始到结束过程的抽象和概括。这个过程包括了众多因素:任务顺序、路线规则、时间时限约束等。
  2. 流程定义。是指对业务过程的形式化表示,定义了过程运行中的活动和所涉及的各种信息。这些信息包括过程的开始和完成条件、构成过程的活动和进行活动间导航的规则、用户所需要完成的任务、可能被调用的应用、工作流间的引用关系,以及工作流数据的定义。
  3. 流程实例。常称为工作,是一个流程定义的运行实例。
  4. 工作流管理系统。与数据库管理系统类似,是一个软件系统。这个程序存储流程的定义,按照所使用的流程定义来触发流程状态的改变,推动流程的运转。这个推动的依据常常被称为工作流引擎。
  5. 流程定义工具。同样是一套软件系统。可能是独立的软件,也可能是工作流管理系统的一部分。
  6. 参与者。回答业务流程中“谁”这个问题。
  7. 活动。活动是流程定义中的一个元素,一次活动可能改变流程处理数据的内容、流程的状态,并可能将流程推动到其他活动中去。活动可以有人来完成,也可以是系统自动的处理过程。
  8. 活动所有者。参与者之一,它有权决定该活动是否结束,当他决定活动结束时,将活动推动到其他活动中,可能是下一个活动,也可能是前一个活动。
  9. 工作所有者。是有权整体控制流程实例执行过程的参与者。
  10. 工作项。代表流程实例中活动的参与者将要执行的工作。

要分析现实中的处理流程,必须首先描述目标系统的流程,这个过程也可以称为建模。

8.6.2 工作流管理系统

是一种“在工作流形式化表示的驱动下,通过软件的执行而完成工作流定义、管理及执行的系统”,其主要目标是对业务过程中各活动发生的先后次序及与活动相关的相应人力或信息资源的调用进行管理,而实现业务过程的自动化。工作流管理系统的六个基本模块的参考模型如下:

  1. 流程定义工具。这部分软件提供图形化或者其他方式的界面给设计者。由设计者将实际工作流程进行抽象,并将设计者提交的流程定义转换为形式化语言描述,提供给计算机工作流执行服务进行流程实例处理的一句。
  2. 工作流执行服务。这个服务程序是工作流管理系统的核心,它使用一种或多种数据流引擎,对流程定义进行解释,激活有效的流程实例,推动流程实例在不同的活动中运转。和客户应用程序、其他工作流服务执行程序进行交互,从而完成流程实例的创建、执行和管理工作。同时这部分软件为每个用户维护一个活动列表告诉用户当前必须处理的任务。如果有必要,还可以通过电子邮件甚至短消息的形式提醒用户任务的到达。
  3. 其他工作流执行服务。
  4. 客户应用程序。这是给最终用户的界面,用户通过使用这部分软件对工作流的数据进行必要的处理,如果用户是当前活动的拥有者,还可以通过客户应用程序改变流程实例的活动,将流程实例推动到另一个活动中。
  5. 被调用应用程序。
  6. 管理和监控工具。

8.7 简单分布式计算机应用系统的设计

8.8 系统运行环境的集成和设计

1. 集中式系统

所有操作都集中于一台主机中,而操作员必须在主机的附近操作。集中式系统常见于银行、保险、证券行业。集中式系统由以下几个部分组成:

  1. 单计算机结构;这种结构简单、容易维护,但是处理能力受到限制。
  2. 集群结构:由多个计算机组成,这些计算机具有类似的硬件平台、操作系统等。通常采用负载均衡、资源共享等方式实现更大的处理能力和容量。
  3. 多计算机结构:由多个计算机组成,这些计算机之间操作环境可能不同。适用于当系统可以分解成多个不同的子系统时。

2. 分布式系统

3. C/S结构

4. 多层结构

这种结构是C/S结构的扩展,典型的分为由存储数据的数据库服务器作为数据层、实现商业规则的程序作为逻辑层、管理用户输入输出的视图层所组成的三层结构。

多层结构形式复杂、工鞥多余,实现多层结构常常需要来实现不同层次建通信的专门程序——管件,也称为中间件。中间件大多数实现远程程序调用、对象请求调度等功能。

5. Internet、Intranet和Extranet

Internet是全球的网络集合,使用通用的TCP/IP协议来相互连接。Internet提供了电子邮件、文件传输、远程登录等服务。Intranet是私有网络,只限于内部使用,也使用TCP/IP协议。Extranet是一个扩展的Intranet。它包括企业之外的和企业密切相关合作的其他企业。Extranet允许分离的组织交换信息并进行合作,这样就形成了一个虚拟组织,现在的VPN技术允许在公用网络上架构支队组织内部开发服务。

8.9 系统过渡计划

1. 直接过渡

当新系统运行时,立即关闭原来的系统

2. 并行过渡

让新系统和旧系统在一段时间里同时运行

3. 阶段过渡

适用于分阶段开发的系统。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容