考试题型包括
分析题
应用题
设计题
编程题
需全面理解和掌握各章节内容,特别是作业和实验所学习实践内容。
期末考试将考核本课程教学大纲中要求的各个目标达成,即本课程培养的各个能力收获。需要同学们切实掌握软件系统分析与设计方法,具备软件系统设计能力。
- 分析题 10 分
给出一个项目的 PERT 图,找出关键路径、最短完成时间、可以延误的任务、不能延误的任务
分析如下架构模型图,请说明该架构是哪种架构?(系统总体架构)

分析如下架构模型图,请说明该架构是哪种架构?(应用架构)

分析如下架构模型图,请说明该架构是哪种架构?(数据架构)

分析以下支付模块的设计类图,该设计遵循了哪些设计原则?

考察服务注册、转发、发现通信模式,写出消息和架构模式名称

分析 web 页面的页面布局和页面导航

- 应用题
在 QQ、银行转账系统架构设计中,分别选择 CAP 模型的哪个方案设计实现?
在如下系统架构设计中,哪个节点重点解决系统高性能访问?

- 设计题
给出就诊业务的合作流程图,绘制编排流程图


以下类模块(客户数据图形分析)设计违背什么设计原则?会带来什么问题?请给出完善后的设计类图。

客户数据访问功能模块为了实现将 TXT 或 Excel 文件中的客户信息输入到数据库中,需要进行数据格式转换。在客户数据访问类(CustomerDAO)中,将调用各外部数据源的转换类方法来实现格式转换,其模块设计类如下:

请给出改进后的设计类图。
说明改进后的类图满足哪些设计模式。
给描述画类图:栖息地、动物、食物、大雁、燕群、翅膀
绘制 ATM 机的部署图,给了相关描述和构件名称,和下面这个差不多

- 编程题
分析说明如下模型中各个类之间关系是否均合理?如有设计不合理,如何完善?并编写 Vehicle 类、Car 类、Bus 类、Taxi 类的 Java 代码。

针对如下民政服务系统的婚姻登记功能设计类图,采用饿汉式单例模式实现该功能的 Java 程序编写,并在主程序中输出消息反馈。

分析如下请假条审批模块功能类图如何应用责任链模式设计?如何编写 Java 程序。

知识目标:
(CO1)掌握大型软件系统分析与设计的基本原理和技术方法,特别是软件系统架构设计、基于模式的软件模块详细设计技术知识与方法。
・能力目标:
(CO2)建立基于软件需求的大型软件系统架构设计建模能力;
(CO3)掌握面向对象设计方法,建立软件模块详细设计建模能力;
(CO4)掌握软件设计模式方法,建立软件设计优化能力;
(CO5)掌握统一建模语言 UML 及其实践应用方法,通过实践培养大型软件系统的面向对象分析与设计能力。
・素质目标:
(CO6)培养学生基于标准与规范撰写软件系统设计报告、清晰阐述解决复杂软件工程问题的专业能力。
# 1. 系统分析与设计概述
本章学习目标如下:
(1)了解信息系统组成、系统类型、利益相关者、系统开发人员;
(2) 理解信息系统软件类型、软件特性、软件质量属性;
(3) 理解信息系统生命周期、信息系统开发活动、信息系统开发工程项目;
(4)理解典型系统开发过程模型的原理、技术特点、适用场景;
(5)了解系统开发策略、系统分析与设计任务、系统开发方法、系统开发工具以及运行环境。
# 1. 信息系统
# 组成
信息系统是一种能够完成对业务数据进行采集、转换、加工、计算、分析、传输、维护等信息处理,并能就某个方面问题给用户提供信息服务的计算机应用系统。

信息化基础设施(计算机、计算机网络、服务器、系统软件等)
应用软件
数据库系统
业务数据
用户
# 类型
业务处理系统
业务处理系统 (Transaction Process System, TPS) 是一类运用 IT 技术对机构业务活动(如订购、销售、支付、出货、核算等)进行信息处理,实现业务处理自动化与提高业务处理效率的信息系统。
# 管理信息系统
管理信息系统((Manage Information System,MIS)是一类以机构信息管理为主导,利用计算机软硬件、网络通信、数据库等 IT 技术,对机构职能进行整体信息化管理,以达到提高机构工作效率和服务价值,并支持机构职能与运营管理的信息系统。
# 决策支持系统
决策支持系统 (decision support system ,简称 DSS) 是一类通过数据分析、模型评估和知识推理等信息处理,以人机交互方式,为决策者解决特定梦略问题提供服务支持的信息系统。
# 专家系统
专家系统 (Expert System, ES)是一种具有获取、存储与利用专家知识解决某类问题的信息系统。它一般是采用人工智能中的知识表示、知识推理、深度学习等技术来模拟通常由领域专家才能解决的复杂问题。
# 办公自动化系统
办公自动化系统(Office Automation,OA)是一种实现办公业务流程信息化、自动化处理的信息系统。
# 知识工作支持系统
知识工作支持系统(Knowledge Work System,KWS)是一种具有强大的数据、图形、图像以及多媒体处理能力,能够在网络化条件下广泛应用多方面信息和技术资源,并为知识工作者提供设计创造、技术创新等服务工具的信息系统。
# 用户分类
系统内部用户
业务人员
主管、经理和总经理
系统外部用户
客户
供应商
合作伙伴
# 开发人员
系统分析人员
系统分析师
业务领域专家
系统设计人员
系统架构师
软件工程师
界面工程师
- 数据库工程师
系统构造人员
软件程序员
硬件工程师
网络工程师
系统集成工程师
系统管理人员
客户经理
项目经理
质量保证人员
测试经理
#
# 1.2 信息系统软件类型
# 类型
应用软件
支撑软件(中间件)
系统软件
# 其他分类
按开发方式分:
通用软件产品
定制软件系统
按授权许可分类:
产品软件
自由软件
共享软件
免费软件
公共软件
开源软件
# 特性
软件是逻辑代码组成的程序集合,非有形物体。
软件不会损耗,但会因失去价值被弃用。
软件是开发人员通过脑力劳动开发出来的,还不能做到生产线制造。
软件还未完全实现标准化构件组装系统。
# 软件开发需解决的本质问题
复杂性 —— 随应用领域、规模、业务不同,软件复杂性差别较大。
一致性 —— 软件都要求与其运行环境的软硬件平台兼容一致。
可变性 —— 因业务过程与需求不断变化,应用软件需具有可变性(如软件版本升级)才能保持软件长久的生命力。
# 质量属性
功能性 (Functionality): 是指软件所实现的功能可达到它所设计规范和满足用户需求的程度。
可靠性 (Reliability): 是指在规定的时间和条件下,软件所能维持其正常的功能操作、性能水平的程度。
易用性 (Usability): 是指用户学习、操作、使用软件所需努力的程度。
效率 (Efficiency): 是指软件系统的处理效能,如处理时间、资源使用率。
可移植性 (Transportability): 是指软件从一个计算机系统环境移植到另一计算机环境的容易程度。
可维护性 (Maintainability): 是指当一个软件投入运行后,若需求发生变化、环境发生改变或软件发生错误时,进行修改所做努力的程度。
可用性 (Availability): 用来衡量软件在特定场景下,用户使用它有效并且满意地达成特定目标的程度。
可扩展性 (Extensibility): 是指软件增加新功能、扩充系统能力的难易程度。可伸缩性 (Scalability): 用来衡量软件在负载变化的情况下,系统处理性能的变化程度。
安全性 (Safety): 用来衡量软件防止非法访问、数据丢失、病毒危害、非授权入侵等事件出现的能力。
健壮性 (Robustness): 用来衡量软件在遭遇意外事件情况时,系统能继续正确执行功能的程度。
互操作 (Interoperability): 用来衡量软件与其他软件系统进行数据交换和服务相互访问的难易程度。
# 信息系统开发过程
信息系统生命周期是指从提出系统的构想开始,经历系统规划、系统开发、系统运行与维护,到系统终止的时间过程。
系统规划阶段

系统需求分析阶段

系统设计阶段

系统构造阶段

系统测试阶段

系统运行与维护阶段

以工程项目方式来管理系统开发过程、支持过程、组织过程中的大量任务活动,才能确保项目在规定时间内按照质量要求完成信息系统开发任务。
# 系统开发过程模型
系统开发过程模型是指开发者在长期工程实践中积累的有效解决系统开发工程活动组织的特定模式。
# 1. 瀑布开发过程模型
在瀑布开发过程模型中,系统开发活动严格按生命周期阶段线性顺序开展,并在每个阶段都会创建和提交大量文档。

模型特点:
系统开发过程活动组织简单,项目阶段划分明确,具有完整的开发文档支持,便于项目管理。
需要大量的文档工作和审查工作,通常会影响系统项目的进度,分散开发人员精力。
用户经过较长周期才能见到信息系统的雏形,对系统项目的反馈迟缓,这会带来项目风险。
在系统开发初期,通常难以获得用户的完整需求,这会导致瀑布开发过程难以开展。
应用场景:
瀑布开发过程模型作为一种经典的系统开发过程模型,只适合于需求十分明确、规模较小的系统项目。
# 1.2.2 原型开发过程模型
在原型开发过程模型中,仅基于初始需求,便可采用快速开发方法与工具,及早给出初始版本的原型系统。用户反馈与新需求进入系统下一版本迭代开发,从而解决瀑布开发过程模型的局限。

模型特点:
能够开发出真正满足用户需求的信息系统,能够较快地提交系统的初始功能版本给用户使用。
需求变更能够很快在系统开发中得到反馈。
系统项目开发难以标记进展的里程碑、项目管理较复杂。
若系统体系结构设计不健壮,多次迭代会使系统稳定性受到挑战。
原型开发过程模型还需要具有系统快速开发能力的工具支持。
应用场景:
原型开发过程模型适合于有大量人机交互界面的系统项目,也适合那些需求初期不太明确的系统项目。
# 1.2.3 螺旋式开发过程模型
螺旋式开发模型也是一种进化迭代式的系统开发过程模型,它兼顾了原型开发过程的迭代特征和瀑布开发过程的系统化与严格审核优点。

模型特点:
引入了其他模型不具备的风险分析,使项目在无法排除重大风险时有机会停止,以减小项目损失。
在系统开发活动由内向外沿着螺线进行迭代开发。每次迭代都将获得系统的一个发布版本,直到获得完全满足用户需求的版本才成为最终系统。
每次迭代开发都进行风险分析固然很好,但项目进度会延后,成本会增加,其项目开发的代价较高。
相对瀑布开发过程模型和原型开发过程模型,螺旋式开发过程模型的项目管理更复杂,需要更多的开发活动组织管理。
应用场景:
螺旋式开发模型适合于大型复杂的系统开发,特别强调系统开发的风险分析。
# 1.2.4 统一软件开发过程模型
统一软件开发过程(Rational Unified Process,RUP)是一种用例驱动的、增量迭代的、以体系架构为中心的系统开发过程模型。

模型特点:
面向对象、用例驱动、以架构为中心开发系统。
增量迭代开发,以质量控制和风险管理为目标。
与 UML 配套、可定制流程框架。
应用场景:
统一软件开发过程模型综合了以前的多种系统开发过程模型的优点,全面考虑了系统开发的技术因素和管理因素,适合于大型复杂系统开发。
# 1.2.5 敏捷软件开发模型
敏捷软件开发(Agile software development)是一种精简的、快速的、增量迭代的系统开发过程模型。

模型特点:
提出一种轻量级开发过程模型方法,强调编程人员与业务专家之间的紧密协作、面对面的沟通、适应需求变化的代码编写。
注重系统开发过程中人的作用、最小化文档编写,快速发布系统版本功能,并能够处理不断变化的用户需求。
解决传统重量级开发过程模型在中小型系统项目中存在成本高、周期长、难以适应快速需求变更等局限。
应用场景:
敏捷开发模式注重系统快速开发,且适用于解决早期需求模糊或需求变更频繁的系统开发项目。
# 系统开发方法与工具
# 系统开发策略
- 自行开发
利用机构自身 IT 人员开发实现信息系统的开发方法。
优缺点:
可以得到满足自身需求的信息系统,并且通过系统开发培养自己的团队。
组织专业规范的系统开发和实施严格的质量保证较困难,通常需要外部咨询和技术培训。
所开发的系统可能存在通用性、稳定性、完整性的局限。
- 委托开发
委托专业 IT 公司针对本机构业务需求定制开发信息系统的开发方法。
优缺点:
能够利用专业 IT 公司的技术优势和信息化经验,以较低的成本开发信息系统。
机构自身可以节省人力资源,可专心于业务优化改进,将精力集中到具有较高价值回报的活动中。
需要配备精通业务的分析人员,与开发团队进行大量的交流、沟通。
依赖于专业 IT 公司的技术支持,后期系统维护较困难。
- 购买商品软件
通过购买商品化软件包,并在此基础上实现信息系统的定制配置。
优缺点:
客户省时省力,短时间就可建立信息系统,效果可以立竿见影。
购买到完全符合机构自身需求的系统不容易。
受限于现有软件局限,难以满足业务需求变化。
- 联合开发
机构与专业 IT 公司联合开发信息系统的开发方法。
优缺点:
充分发挥客户团队和开发团队的优势,有利于自身技术力量的培养。
依赖于双方精诚团结,自身需要有一定的系统分析与设计能力。
# 系统开发方法
- 结构化方法
结构化方法是面向过程的软件开发方法,由结构化分析方法、结构化设计方法和结构化程序设计方法组成。
其基本思想如下:
自顶向下
逐步求精
系统模块分解
以过程为中心构建软件系统
结构化方法典型技术:
数据流图、数据字典、层次结构图设计、E-R 关系图设计、程序流程图设计、伪代码设计、结构化编程等。
结构化方法优缺点:
简单实用、技术成熟、容易应用。
但对规模较大及处理复杂的软件系统项目不太适合,存在难以适应需求变更,难以解决软件复用,难以进行软件维护,难以提高软件生产效率等问题。
当前软件开发现状:
现在的软件系统项目大多具有功能复杂、规模较大、异构平台、快速交付、可维护性和可靠性要求高等特性。结构化方法不能适应这些要求。需有新的软件开发方法去应对。
- 面向对象软件开发方法
面向对象方法是一种将面向对象思想应用于软件开发过程、指导软件开发活动的方法。
面向对象分析
面向对象设计
面向对象编程
面向对象基本思想:
客观世界是由各种对象(Object)组成,复杂对象可以由简单对象组成。
类 (Class)是具有相同特征对象的模板,将对象的属性数据和操作程序封装在一起。
对象之间通过消息(Message)传递实现行为交互,以模拟现实世界中不同事物之间的联系。
面向对象方法优缺点:
与人的思维方式一致
稳定性好
可重用性好
可维护性好
掌握面向对象技术方法需要更多的时间
面向对象方法适合的软件项目类型:
面向对象方法适合需求变更较频繁、功能复杂、规模较大、异构平台、快速
交付、可维护性和可靠性要求高的软件系统项目。
- 基于构件软件开发方法
基于构件软件开发方法是一种基于分布式对象技术、强调通过可复用构件设计与构造软件系统的开发方法。
从业务功能视角出发,采用比面向对象方法更高一级的抽象技术设计实现软件,其软件重用度可以得到提高。
将软件开发的重点从程序编写转移到了基于已有构件的组装,以更快方式构造系统,减轻支持与升级大型系统所需要的维护负担,从而降低软件开发的费用。
优缺点:
构件开发使得软件重用度、开发效率得到提高,确保软件质量。
软件构件开发是与编程语言紧密联系,容易导致构件接口标准不统一,不同开发语言实现的构件难以实现互操作。
- 面向服务的系统开发方法
基于面向服务思想,采用松耦合、粗粒度软件功能重用的系统开发方法。
面向服务的系统开发方法关注点是业务,它直接映射到业务,强调 IT 与业务的对齐,以业务服务为核心元素来封装业务功能或已有应用系统。
服务比构件的粒度更大,更加匹配机构信息化应用中的业务,可以实现更高级别的软件重用。
优缺点:
可以实现跨平台的功能复用,也可复用现有应用系统。
开发技术复杂,需要解决较多的分布式应用难点技术问题。
# 系统开发工具与环境
# 开发工具
项目管理工具 (Project)
项目管理工具 (Project)
# 习题
1. 瀑布开发过程模型的局限:
• 缺乏灵活性:瀑布模型是一种线性顺序的开发方式,各个阶段严格按照顺序执行,需求变更或调整较为困难。一旦进入下一个阶段,之前的工作就难以回溯或修改。
• 需求不稳定时不适用:在需求不明确或需求变更频繁的情况下,瀑布模型很难适应这些变化,因为它通常假设需求在项目开始时就已经完全明确。
• 测试阶段推迟:测试阶段通常安排在开发的后期,这可能导致在发现问题时已经很难修改,修复成本高。
• 客户参与较少:瀑布模型强调文档驱动,客户或最终用户通常在需求阶段之后参与较少,可能导致最终产品与用户期望不符。
2. 原型开发过程模型能解决瀑布开发过程模型的哪些问题?:
• 需求不明确时的灵活性:原型模型通过快速构建一个可交互的原型来帮助用户明确需求。用户可以在早期看到系统的雏形,从而更容易提出修改意见。
• 需求变更的适应性:由于原型是可迭代的,用户反馈能够迅速被整合进系统中,适应需求的不断变化。
• 增加客户参与:原型开发过程强调客户在开发过程中的参与,客户可以在原型的基础上提出修改建议,这帮助确保最终产品更符合用户需求。
3. 螺旋式开发过程模型相对瀑布开发过程模型和原型开发过程模型的改进:
• 风险管理:螺旋模型通过引入风险评估和管理,特别适用于风险较高的项目。每一轮的开发都会评估和分析项目的潜在风险,并采取措施应对。
• 迭代开发:与瀑布模型不同,螺旋模型是迭代的,每一轮迭代都包含需求分析、设计、实现、测试等多个阶段,使得项目更具灵活性。
• 更高的客户参与度:螺旋模型强调每个阶段的客户反馈,可以确保产品更接近用户需求。
• 适用于复杂和高风险项目:螺旋模型能够灵活应对复杂项目的需求变更,且在每一阶段都进行风险评估和修正,适合大规模或高风险的项目。
4. 统一软件开发过程模型适合哪类系统开发?
统一软件开发过程(Unified Process, UP)是一种面向对象的开发模型,适合于复杂、长期、需求多变的大型系统开发。特别适用于需要可扩展性、维护性和灵活性的企业级应用开发。UP 强调需求的可追踪性,提供了明确的开发过程,适合开发企业管理系统、信息系统等。
5. 敏捷软件开发过程模型适合大型系统开发吗?
敏捷开发通常更适合小到中型项目,尤其是那些需求不明确或变动频繁的项目。对于大型系统,尽管敏捷开发方法提供灵活性和响应快速变化的能力,但其实施较为复杂且需要大量团队协作和高效沟通,因此可能面临一些挑战。大型系统开发中的敏捷方法通常需要结合其他模型(如 Scrum、DevOps 等)或通过分阶段迭代来实现。
6. 敏捷软件开发过程模型的优点:
• 响应需求变化:敏捷开发强调快速迭代和频繁交付,可以根据反馈及时调整开发方向,以更好地适应用户需求变化。
• 提高开发效率:通过短周期的迭代开发,可以更早地发现并解决问题,提高开发效率。
• 客户参与度高:敏捷开发重视客户的持续参与,客户可以随时反馈需求,确保开发的产品更符合其期望。
• 灵活性:敏捷开发能够根据项目进展调整优先级和计划,避免了固定流程的僵化。
• 增强团队协作:敏捷开发强调团队成员之间的紧密协作和快速沟通,能够提高团队效率和质量。
# 2. 面向对象基础与建模语言
(1) 理解对象、类等基本概念和面向对象思想;
(2)了解统一建模语言 UML 的基本元素、模型图形及其作用;
(3)了解业务流程建模与标注语言 BPMIN 及其作用。
# 2.1 面向对象基础
面向对象概念
对象
类
类是一组具有相同属性与行为的对象集合,物以类聚。
类是抽象,对象是具体。
类是集合,对象是集合中的个体。
类的属性可以没有值,对象的属性必须分配值。
- 面向对象分析、设计、编程思想
# 2.2 UML 建模语言
UML 建模语言,用例图、活动图、类图、顺序图、通信图、状态机图、构件图、部署图、包图,UML 通用机制和扩展机制
# 1. 用例图
用例图模型元素:

系统用例图 ( System Use CaseDiagram)从系统分析员角度对系统需求功能进行描述的模型图。
用例是系统的功能点抽象。
角色是系统的用户类型抽象。
角色与用例、用例与用例之间的关联表示它们存在一定的联系。

业务用例图 ( Business Use CaseDiagram)从用户角度对业务功能进行描述的模型图。
用例是业务的功能点抽象。
角色是业务的用户类型抽象。
角色与用例、用例与用例之间的关联表示它们存在一定的联系。

# 2.2 活动图
活动图模型元素:

活动图 (Activity Diagram)是描述用例内部活动执行顺序以及活动输入输出的模型图。
活动图还可用于描述业务流程、算法流程、系统控制流程等。

# 类图
类图模型元素:

类图 (Class Diagram)是描述系统由哪些类组成,即面向对象程序组成。
它也用于描述表示系统中类程序之间的关系,直观呈现系统程序的静态结构。

# 顺序图
顺序图模型元素:

顺序图 (Sequence Diagram, 也称序列图)是一种描述对象之间消息交互的模型图。
用来反映对象之间的动态协作关系,也就是对象之间的交互关系。

# 通信图
通信图模型元素:

通信图 (Communication Diagram)是表现对象间直接消息交互关系的模型图。
它展现了多个对象在协同工作达成共同目标的过程中互相通信的情况。
通过对象和对象之间的链接、发送的消息来显示对象之间的交互关系。

# 状态机图
状态机图模型元素:

状态机图 (State MachineDiagram) 是描述一个对象在其生命周期内所经历的各种状态以及状态变迁的模型图。
描述类的对象所有可能的状态以及事件发生时状态的转移条件。

# 构件图
构件图模型元素:

构件图 (Component Diagram)是描述系统的构件组成及其关系的模型图。
描述软件实现的物理结构,从而反映出基于构件的软件实现。

# 部署图
部署图模型元素:

部署图 (Deployment Diagram) 是表示系统构件在运行环境节点中的部署方案。
从部署图还可以获知软件和硬件节点之间的物理拓扑、处理节点以及运行环境情况。

# 包图
包图模型元素:

包图 (Package Diagram)是采用类似文件夹的包符号表示模型元素的组织结构模型图。包被描述成文件夹,可以应用在任何一种 UML 图上。
系统中的每个元素都只能为一个包所有,一个包可嵌套在另一个包中。

UML 通用机制和扩展机制
・UML 通用机制:UML 图中添加描述信息,完善 UML 语义表达
– 规格说明(Specification)
– 修饰(Adornment)
– 通用划分(General Division)
数据库原理及应用
・UML 扩展机制:对 UML 进行扩展和调整,使其与一个特定的方法、组织或用户相一致
– 构造型(Stereotype)

– 注释(Note)
– 约束(Constraint)
– 标签(Tagged values)
1、规格说明(Specification)
# 2.3 BPMN 建模语言
BPMN 建模语言
BPMN (Business Process Modelling Notation)定义了一套标准的业务流程图符号,使用这些符号可以创建描述业务流程操作的图形化模型。
BPMN 还支持生成可执行的业务流程执行语言(BPEL)。BPMN 可以基于 WS-BPEL 转换为软件流程组件。使用 BPMN 可以建模描述机构内部业务流程能力,其模型可以作为设计人员、管理人员和业务流程实现人员交流业务活动的桥梁。







# 3. 系统规划
(1) 了解系统规划的目标、任务及意义;
(2)理解系统规划的典型方法;
(3) 掌握系统规划方案设计方法;
(4) 掌握项目计划方法;
(5) 掌握项目可行性分析方法。
# 定义
系统规划是指组织机构在进行信息化建设前,对组织机构的战略目标、机遇与挑战、经营现状、信息化需求等因素进行调研与分析,然后为组织机构未来发展提供信息系统建设方案与项目计划。
# 意义
系统规划提供了机构信息化建设的基本纲领和总体指向。
系统规划是工程项目实施的前提与依据。
做好系统规划可避免盲目信息化建设给机构带来巨大的损失。
# 目标
系统规划目标是针对组织机构的使命、战略目标、经营现状、发展机会与面临挑战等因素进行综合分析,对组织机构信息化建设做出可行的信息系统建设方案。
# 任务
根据组织机构使命及其战略目标,制定信息系统建设总体目标与愿景;
针对组织机构信息化需求,确定信息系统总体框架、技术路线与实施方案;
在充分考虑组织机构的技术、设备和人力资源等因素下,制定组织机构的信息系统实施建设计划,并分析评估信息系统建设方案可行性。
# 规划方法
# 业务系统规划法
业务系统规划法(Business System Planning,BSP)是 IBM 公司在 20 世纪 70 年代提出的一种制定信息系统规划方法。
# 业务流程重组法
业务流程重组法(Business Process Reengineering,BPR)是由美国企业管理专家在 20 世纪 90 年代初期提出的一种围绕业务流程改造的系统规划方法。
# 价值链分析法
价值链分析法 (Value Chain Analysis,VCA) 是由美国哈佛商学院教授 Porter 提出来的一种寻求确定企业竞争优势的规划方法。
# 战略目标集转移法
战略目标集转移法(Strategy Set Transformation, SST)是 William King 在 1978 年提出一种将组织机构战略目标集(使命、目标、战略等)转变为信息系统战略目标的规划方法。
# 关键成功因素法
关键成功因素法(Key Success Factors,KSF)是哈佛大学教授 William Zani 于 1970 年提出的以关键因素为依据来确定系统信息需求的规划方法。
# 项目计划
# 定义
项目计划是根据信息系统建设目标要求,对信息系统建设所涉及项目任务进行总体工作安排。
工期预算
为了制定项目进度计划和估算成本,首先需要对项目各个任务活动工期进行估算。项目工期则由各个任务活动工期按照关键路径计算得到。
三点估计法
项目经理或系统分析人员根据历史数据经验对某类任务活动的工期完成时间分别给出乐观时间(记为 a)、悲观时间(记为 b)和正常时间(记为 m)。采用如下经验公式计算得到任务活动工期 E。
E=(a+4m+b)/6
例:某软件功能模块在正常情况下需要 7 天时间完成编程。若由一个具有丰富编程经验的程序员进行编程实现,需要 6 天时间完成。但由一个经验不足的程序员编程这个模块可能需要 14 天时间才能完成。请问该功能模块的工期该如何估算?
按照 “三点估计法” 计算公式,可估算得到该模块的编程工期为:
E=(6+4*7+14)/6=8 天
德尔菲法
德尔菲法用于项目任务活动工期估算的步骤如下:
1)组织者发给每位专家一份项目任务活动规格说明和记录表格,请专家估算每个活动的工期;
2)每位专家针对每个活动分别给出工期的最短值 ai、最可能值 mi、最长值 bi;
3)组织者按照如下估算法公式,计算每位专家估算工期的加权平均值 Ei;
Ei= (ai +4*mi + bi)/6
然后,再将所有专家的工期估算平均值按照如下公式计算期望值:
E= (E1+…………+En)/n
4)组织者汇总各位专家估算值与期望值的偏差,形成图表对比,再分发给各位专家,让专家比较自己同他人的不同意见,修改自己的意见和判断;
5)重复多次,最终获得一个多数人认可的项目任务活动工期估算值。
例:某公司准备研发一个新技术产品,需要估算该项目任务的工期。组织者邀请了三位专家独自对该任务工期(天数)进行估算。经过三轮调查反馈,形成下表所示的估算数据。

按照德尔菲法估算方法,经过三轮反馈数据的统计处理,可以确定该任务工期为 74 天。
进度安排
项目进度安排是根据项目任务活动分解、任务活动顺序、各任务活动估计时间和所需资源分析,制定出项目起止日期和任务活动开展时间的工作安排。
项目任务网络中最长的一条路径称为关键路径,它决定了完成该项目的工期。
关键路径上的每一项任务都是关键任务。这些任务的完成时间一旦有延迟,就会影响项目的完成时间。

# 甘特图法
甘特图用于项目计划与进度管理。它把一个项目划分为若干任务,并用任务条可视化展示。
甘特图让项目开发人员直观看到项目中各任务和每项任务开始日期、结束日期,任务持续时间,哪些任务之间有重叠,一个项目工程的开始时间和结束时间。


# PERT 图方法
PERT 图采用网络图形式来表达项目中各项任务进度以及它们之间的相互关系。
在 PERT 图基础上进行项目任务网络分析和时间估计,用于协调整个计划的完成。


习题:
设计题
1. 针对一个选课系统的项目计划,设计项目进度安排的甘特图。
- 甘特图设计
项目背景
设计一个大学选课系统,系统的功能包括学生注册、课程管理、课程选择、教师管理、管理员功能等。项目计划周期为 6 个月。
项目进度安排
以下是主要任务及其时间安排:

1. 甘特图会以条形图的形式表示每个任务的开始和结束时间。
2. 每个任务都有不同的颜色标识,便于区分。
3. 任务之间的依赖关系在甘特图中用箭头标注,例如 “系统架构设计” 完成后才能开始 “数据库设计”。
2. 针对一个选课系统的项目计划,设计项目进度安排的 PERT 图。
项目背景
选课系统涉及多个模块,需要分析每个任务的依赖关系及完成时间。通过 PERT 图可以明确关键路径,优化资源分配。
PERT 图节点与任务
以下是项目主要任务及其时间估算:

PERT 图流程与关键路径
• 节点顺序与依赖关系:
• A → B → C → D → E → F → G
・部分任务可以并行,例如:D(前端开发)和 E(后端开发)可以同时进行。
• 关键路径:
・关键路径是完成项目的最短时间路径,总持续时间约为 24 周(6 个月)。
・关键路径任务:A → B → E → F → G。
PERT 图特性
1. 图中用圆圈表示任务节点,用箭头表示任务的依赖关系。
2. 在每个节点中标注任务的名称和期望完成时间。
3. 使用不同颜色突出关键路径。
# 4. 系统需求分析
(1) 掌握需求采集方法与需求确定方法;
(2) 掌握利用 BPMN 建模业务需求的方法;
(3)掌握利用 UML 建模系统功能需求的方法;
(4) 熟悉需求规格说明书的文档结构和掌握需求管理方法。
# 1. 需求采集与需求确定
# 研究现有文档与系统
组织机构图
系统规划文档
工作规范文档
业务单据
数据报表
反馈意见
领域知识
现有系统
# 4.2 业务流程建模
- 业务流程模型是用来描述业务活动处理过程的模型,基于 BPMN 建模语言可以实现业务处理过程的可视化建模。

# 业务用例建模
业务用例模型是一种描述业务功能的模型,它需要直观地抽象出业务工作的功能、人员角色以及业务边界,可采用面向对象的 UML 业务用例图进行建模。


# 系统用例图建模
针对复杂系统或大型系统进行功能需求分析,可采用面向对象的 UML 用例图建模方法


# 活动图建模
在系统需求分析中,除了定义功能用例外,还需要描述该功能用例的内部处理流程。这就需要采用 UML 活动图建模用例的行为过程。


# 分析类图建模
在系统分析阶段,除了建立用例图与活动图模型外,还可进一步建立分析类图模型,用于描述系统由哪些分析类来实现用例功能。
补充:
多重性关联 :多重性关联关系又称为重数性(Multiplicity)关联关系,表示两个关联对象在数量上的对应关系。在 UML 中,对象之间的多重性可以直接在关联直线上用一个数字或一个数字范围表示。
表示方式 多重性说明
1…1 表示另一个类的一个对象只与该类的一个对象有关系
0…* 表示另一个类的一个对象与该类的零个或多个对象有关系
1…* 表示另一个类的一个对象与该类的一个或多个对象有关系
0…1 表示另一个类的一个对象没有或只与该类的一个对象有关系
m…n 表示另一个类的一个对象与该类最少 m,最多 n 个对象有关系 (m≤n)

分析类图建模步骤
从问题领域抽取类
定义类名及属性
确定类之间关联
增量迭代完善类图
抽取类的方法
用例驱动方法
从用例模型抽取类的方法:
分析用例图模型,抽取含有业务数据的实体,作为系统的第一批实体类,如 Grades 类和 ReportCard 类。
将用例的参与者作为第二批实体类,如 Teacher 类、Student 类和 Administrator 类。
习题
以一个简化的银行 ATM 机系统为例进行需求分析,给出此系统的 UML 用例图、
活动图和类图。
简化的银行 ATM 机系统具有用户身份认证、余额查询、取钱、存钱和转账这
五个基本功能。





# 5. 系统架构设计
(1)了解系统设计过程、设计活动、设计方法;
(2)理解系统的架构组成、架构方法、架构设计;
(3)理解基于客户机 / 服务器的、基于构件的、面向服务的架构技术;
(4) 理解非功能需求如何影响架构设计;
(5) 掌握软件架构的 UML 建模设计方法。
# 分布式系统
# CAP 定理


BASE 模型



# 解决高性能访问
# 1.DNS 负载均衡

# 2. 硬件负载均衡器

# 3. 软件负载均衡器

# 4. 混合应用负载均衡器

# 容错性
集中式系统容错性
分布式系统容错性
# 高可用架构设计
主备模式
互备模式
集群模式
# 分布式数据库架构设计
# 1. 主备架构设计


# 5.2 双主架构设计


# 5.3 单主多从架构设计


# 5.4 双主多从架构设计


# 冗余技术

# 系统总体架构
系统总体架构是从全局层面给出系统各种组成要素之间结构关系。它通常包括基础设施、运行平台、应用软件、业务部门、信息数据、用户,以及外部系统等


# 系统拓扑结构
系统拓扑结构是指从系统基础设施平台层面描述节点与节点之间的通信连接关系。节点是指系统中处理功能相对独立的物理设备,如 PC 计算机、服务器、外围设备等。
系统拓扑结构设计是对系统基础设施平台的设备节点在网络环境中的结构关系进行设计,包括节点分布、节点类型、节点拓扑关系以及节点之间的通信联系。

# 系统拓扑架构类型

# 系统拓扑架构案例

建模实践练习 —— 电子商务系统高可用拓扑架构设计

# 系统数据架构
系统数据架构是指从数据管理视角所描述的系统架构,它通常用来反映系统的各类数据资源组织与存储架构。
系统数据架构不仅需要反映机构的数据结点分布关系。
还需考虑数据资源的存储结构形式,如文件存储、数据库存储或数据仓库存储。

# 系统数据分层架构设计
在大数据应用系统中,按照数据不同处理要求,可以将它们组织到不同层次的模块中进行数据管理。

# 系统数据治理架构设计
在信息系统中,一般是按照业务管理的数据治理需求,将数据资源部署到不同业务部门系统服务器进行数据访问与权限管理。系统数据治理架构与组织机构的数据管理职能有直接关系。

# 系统数据存储架构设计
在信息系统中,一些数据资源需要采用文件系统存储,另外一些数据资源需要采用数据库系统存储,还有一些数据资源则需要数据仓库系统进行数据存储。每类存储系统在设计上需要满足应用需求,如支持高可用、高性能的存取访问。

# 数据架构设计案例 —— 电子政务系统数据架构

# 系统应用架构
系统应用架构
系统应用架构是指从应用功能视角所描述的系统架构。系统应用架构关注应用功能划分、应用功能配置、服务访问、服务管理等要素。
应用架构类型
企业级应用架构:在企业信息化全局层面,企业级应用架构起到了统一系统规划、承上启下的作用,向上承接了企业战略发展方向和业务模式,向下规划和指导企业各个 IT 系统的定位和功能。企业级应用架构一般是在系统规划阶段设计。
系统应用架构:在开发单个信息系统时,设计系统应用架构,并考虑系统各个层次的功能构件组成,如前端展示层、业务处理逻辑层、数据访问层的功能模块结构。系统应用架构一般是在系统开发阶段设计。
应用架构层次设计

# 应用架构设计案例 —— 供应商管理系统应用架构

建模实践练习 ——— 供应链系统应用架构设计

# 软件体系架构
软件体系架构(简称软件架构)是一种从软件视角所描述的系统架构,它对软件系统的结构、行为进行高层抽象,一般通过构件、连接件、配置、端口、角色等图符元素进行描述。
构件 (component) : 具有特定功能的、可重用的软件模块。
连接件 (connector) : 用以表示构件之间的交互,如过程调用、事件广播、交互协议等。
配置 (configuration): 用于对构件与连接件的拓扑逻辑、语义约束等说明。
端口 (port): 表示构件接口与外部环境的交互点。
角色 (role) : 连接件的参与者,如事件消息的发布者与接受者。



# 软件架构风格
软件架构风格定义
软件架构风格是指针对领域共性问题提供通用的软件架构解决方案,它反映了领域中众多系统所共有的软件架构模式。
软件架构风格作用:用于指导开发者参照软件架构风格设计本软件系统架构,合理地将构件、子系统有效地组织成一个完整的软件系统。
软件架构风格要素
软件架构风格描述了特定应用领域中软件系统构件组成的惯用模式,其要素如下:
软件架构包含哪些类型的构件与连接件?
组成系统的结构模式是什么?
基本的计算模型是什么?
架构的基本特性是什么?
架构应用的场景是什么?
架构的优缺点是什么?
软件架构风格应用意义
定义了一类软件系统架构的要素和一组指导系统架构设计的规则。
可促进软件系统设计的复用,使得一些经过实践验证的软件架构方案能够可靠地解决新问题。
通过对标准软件架构风格的应用可支持不同系统之间互操作性,以便于实现系统集成。
在特定设计空间下,便于对软件系统相关设计作出分析。
软件架构风格分类
风格类型 典型风格
数据流风格 批处理序列架构、管道 / 过滤器架构
调用 / 返回风格 主程序 / 子程序架构、面向对象架构、分层体系架构
独立构件风格 进程通讯架构、事件驱动架构
虚拟机风格 解释器架构、基于规则的系统架构
客户 / 服务器风格 客户 / 服务器架构、浏览器 / 服务器架构
面向服务风格 面向服务架构 (SOA)、微服务架构
仓库风格 数据共享体系架构、黑板系统架构
# 1. 分层体系架构
分层体系架构采用层次化方式组织功能构件,每一层都是为上一层提供服务,并使用下一层提供的功能服务。

将软件系统分解设计为若干层次。每一层都有清晰的功能处理分工,各层不需要知道其他层的细节,层与层之间仅通过接口通信。
用户对软件系统的访问请求将依次通过各层功能逻辑构件对下层进行调用访问处理。通常不允许跨层调用访问。
应用案例:Linux 系统架构

分层体系架构优点:
将复杂系统设计分解到各层,使整体设计可以得到简化,其系统结构清晰。
支持系统功能扩展设计,每层的功能修改最多只影响相邻层。
只要给上层提供标准接口,就可实现功能复用。
分层体系架构缺点:
并不是每个系统都可以很容易地划分层次,此外,系统层次划分还没有统一的方法。
层次过多,会造成系统性能降低。
当用户请求大量增加时,必须依次扩展每一层处理能力。如果某层的内部是耦合的,系统扩展较困难。
# 5.2 数据共享体系架构
数据共享体系架构是一种以数据存储服务器为中心,为客户软件提供数据共享、数据交换访问的软件架构风格。

在数据共享体系架构中,各个客户软件相互独立,它们通过共享数据存储实现数据交换。
客户软件之间不存在控制调用关系。
一个客户软件对共享数据进行了修改,其他客户软件可以获得数据变更信息。
应用案例:基于数据共享体系架构的数据挖掘与分析系统

数据共享体系架构优点:
体系架构简单,容易实现软件开发。
可有效地实现大量数据共享,新客户软件加入系统,无须考虑其他客户软件的存在。
只要遵循共享数据访问接口,各个客户软件可以独立执行。
数据共享体系架构缺点:
当共享数据结构发生变化,各客户软件都需要进行数据访问调整,通常比较麻烦。
当客户软件大量增加时,共享数据存储服务器将面临性能压力。
共享数据存储服务器作为系统的中央单元,若没有考虑高可用性方案,它一旦故障将导致整个系统无法运行。
共享数据存储实现分布式处理较困难。
# 5.3 事件驱动体系架构
事件驱动体系架构是一种基于事件与消息机制实现软件构件之间进行通信的软件架构。
构件(子系统) 之间并不直接交互,而是通过触发一个或多个事件,隐式调用另一构件执行。
各构件加入系统时,需要在事件管理器中注册相关事件。一旦事件触发,系统将隐含调用注册该事件的构件进行处理,并将处理结果返回事件发布者构件。

应用案例:Windows 事件驱动模型

事件驱动体系架构优点:
具有良好的可扩展性。通过注册可引入新的构件,而不影响现有构件。
便于软件维护。只要构件名及其接口不变,可以用一个构件代替另一个构件。
构件之间耦合性低,容易实现软件重用。
事件驱动体系架构缺点:
事件驱动削弱了构件对系统的控制能力。一个构件事件触发时,并不能保证其它构件会对其进行事件响应。
消息传送机制不能很好地解决数据交换问题。
# 5.4 客户机 / 服务器体系架构
客户机 / 服务器软件架构是一种典型的分布系统体系架构,其软件分为客户端构件和服务端构件,客户端构件通常在客户机上运行,服务端构件在服务器上运行。

客户机 / 服务器架构采用分布式系统模式,它通常将界面展示、应用逻辑与数据存取构件分布在多个节点机上进行处理。
客户端构件为完成特定功能,需要向服务端构件发出请求。服务端构件接收客户端构件请求进行处理,并将结果返回请求者。
客户端与服务端构件一般是分别部署在客户机和服务器中,通过网络连接进行通信,也可以将它们部署在同一物理机器内部。
# 5.4.1 C/S 架构原理

应用案例:基于 C/S 架构的企业固定资产管理平台

C/S 架构优点:
可实现分布式计算处理,有利于系统负载分担。
交互性强、具有安全的存取模式、响应速度快、利于处理大量数据。
C/S 架构缺点:
缺少通用性,系统维护、升级需要重新安装部署,增加了维护和管理的难度。
只限于小型的局域网应用。
# 5.4.2 B/S 架构原理

应用案例:基于 B/S 架构的物流管控系统平台

B/S 架构优点:
分布性强 —— 服务器可以在任何地点运行。
访问方便 —— 只要有网络、浏览器,就可以对系统应用进行访问。
系统处理负载能力强 —— 可以将负载分布在 Web 服务器、应用服务器、数据库服务器处理。此外,通过负载均衡、集群技术可以支持更大负载处理。
系统运维方便 —— 只需要在服务器进行功能修改与发布,即可实现所有用户访问的同步更新。
用户共享性强 —— 可以支持不同地点用户共享访问系统。
B/S 架构缺点
个性化处理、人机交互性能不如 C/S 架构软件。
在系统安全性设计需要考虑更多内容。
# 4.3 C/S 与 B/S 的混合架构


# 5.5 微核体系架构
微核体系架构又称为 “插件架构”,系统基本核心功能在软件内核中实现,其功能较少,系统大部分功能和业务逻辑都通过插件实现。
微核体系架构将待开发的目标软件分为软件内核和插件两个部分。
内核实现软件的基本核心功能和插件管理功能。
插件实现软件功能的运行时扩展与补充。它是一种按照统一插件接口规范实现的功能程序。

应用案例:Eclipse 开发平台

微核体系架构优点:
良好的功能扩展性,需要什么功能,开发一个插件即可。
插件之间是隔离的,可以独立的加载和卸载,使得它比较容易部署。
可定制性高,适应不同的开发需要。
可以渐进式地开发,逐步增加功能插件。
微核体系架构缺点:
伸缩性差,内核通常是一个独立单元,不容易做成分布式。
开发难度相对较高,因为涉及到插件与内核的通信,以及内部的插件登记机制。
# 5.6 微服务架构
微服务架构 (microservices architecture)是面向服务架构 ( service-oriented architecture,SOA)的轻量级实现版本。

将应用软件功能设计为若干服务构件,服务构件之间相互协调与配合,为用户提供功能服务。
每个服务构件运行在独立的进程中,服务构件之间采用轻量级通信机制进行消息交互。
每个服务构件都围绕业务进行构建,并且能够独立部署到运行环境。
这些服务都是分布式的,互相解耦,通过标准通信协议(如 REST、SOAP)进行交互。
应用案例:淘宝开放平台

微服务架构优点:
支持不同开发语言
微服务架构缺点:
由于强调互相独立和低耦合,服务可能会拆分得很细。这导致系统依赖大量的微服务,变得凌乱和笨重,性能也会不佳。
分布式处理使得微服务较难实现原子性操作,交易回滚会比较困难。
# 软件架构模式
# 软件架构模式定义
软件架构模式就是针对特定需求问题及其环境,所给出通用的软件架构设计解决方案。软件架构模式相对软件架构风格,所涉及范围要窄些,解决更具体问题。
软件架构风格 软件架构模式
分层架构风格 代理者模式
数据共享架构风格 发布 / 订阅模式
事件驱动架构风格 多客户 / 单服务模式
客户 / 服务器风格 多客户 / 多服务模式
微核架构风格 多层客户 / 服务器模式
面向服务风格 异步消息通信模式、同步消息通信模式
数据流风格 服务代理转发通信模式
虚拟机风格 复合事务模式
异构风格 MVC 模式、MVP 模式、MVVM 模式

# 软件架构结构模式
在软件架构模式中,反映软件构件组成及其控制关系的结构模式主要有如下几种:
# 1. 代理者模式
在代理者模式的软件架构中,需要使用代理者扮演客户端和服务端的中介角色。
代理者使得客户端不再需要知道某个服务在哪里,就可以获得这个服务,从而使得客户端可以方便地定位服务。


案例:客户 client 对象在访问一个业务服务(EJBService、JMSService)时,并不知道该服务位置,可通过业务代理(BusinessDelegate)进行查找,然后可以定位该服务,并对该服务进行请求访问。

# 5.2 集中式控制模式
在集中式控制模式的软件架构中,中央控制构件按照特定对象状态机逻辑对系统全局行为进行控制操作。
中央控制构件接收输入构件或用户界面构件的输入操作。
中央控制构件根据输入事件引发的系统状态变迁,对相关部件实施操作控制,从而实现系统功能控制。

案例:在微波炉控制系统中,设备的中央控制构件采用集中式控制模式对各个执行部件进行控制操作。

# 5.3 分布式控制模式
在分布式控制模式的软件架构中,系统控制分布在多个控制构件之中,不存在总控全局的单一构件。
每个控制构件按照特定对象状态机逻辑对系统特定部分的行为进行控制操作。
多个控制构件通过消息通信协作完成整个系统的控制处理。

案例:在一个植物工厂控制系统中,其控制系统对植物生长所需要的光照、温度、湿度等参数进行控制,其控制方式采用分布式控制体系架构模式对各个执行部件进行控制操作。

# 5.4 多层控制模式
在多层控制模式的软件架构中,系统控制分布在多个控制构件之中,此外,通过协调者构件控制所有控制构件实现整个系统的控制。
协调者构件提供全局控制,而每个控制构件按照特定对象状态机逻辑对系统特定部分的行为进行控制操作。
协调者控件发布命令到各个控制构件执行控制操作,同时协调者控件也从控制构件接收状态消息。

案例:在一个植物工厂控制系统中,其控制系统对植物生长所需要的光照、温度、湿度等参数进行控制,其控制方式也可采用多层控制体系架构模式对各个执行部件进行控制操作。

# 5.5 抽象分层模式
在抽象分层模式的软件架构中,复杂的软件构件关系被抽象到不同的功能层次。
每个层次构件只能访问它的相邻下层服务同时也只对相邻的上层提供服务。
相邻上下层次构件之间通过请求调用访问、返回响应消息方式进行交互实现系统功能处理。

案例:在一个 Unix 系统中,软件系统采用分层架构组成,分别由内核、系统调用、shell / 实用程序 / 公共函数库、应用程序层次组成。

# 5.6 多客户 / 单服务模式
在多客户 / 单服务模式的软件架构中,软件构件被部署到多个客户端结点和一个服务端结点。
各客户端结点的软件构件通过网络连接访问服务端结点上运行的服务。
在本模式下,多个客户端构件可并发向一个服务端构件提出服务请求,服务端构件一次将处理结果返回给请求的客户端构件。

案例:在银行 ATM 系统中,每个银行网点都有多台 ATM 客户端结点通过网络连接银行业务系统,其软件系统采用多客户 / 单服务模式体系架构。

# 5.7 多客户 / 多服务模式
在多客户 / 多服务模式的软件架构中,软件构件被部署到多个客户端结点和多个服务端结点上运行。
客户端构件通过网络连接访问多个服务器结点上运行的服务。
在本模式下,多个客户端构件可并发向多个服务端构件提出服务请求,服务端构件各自将处理结果返回给请求的客户端构件。

案例:在一个支持多家银行互联互通的 ATM 系统中,每个银行网点都有多台 ATM 客户端结点通过网络连接银行业务系统,它们的软件系统采用多客户 / 多服务模式体系架构。

# 5.8 多层客户 / 服务模式
在多层客户 / 服务模式的软件架构中,除了基本的客户端层次和服务端层次外,还有一个同时扮演客户端角色和服务端角色的中间层。
中间层对于它的服务层而言是一个客户端,但对其他客户端而言又是一个服务端。
客户端、中间层、服务端的结点通过网络进行通信,支持多个客户端构件向服务端构件提出服务请求,服务端构件将处理结果返回给请求的客户端构件。

案例:在一个具有三层客户 / 服务模式架构的银行 ATM 系统中,“银行服务” 层向 “客户端” 层提供服务,同时它又是 “数据库服务” 层的一个客户端。

# 软件架构通信模式
软件架构通信模式关注构件之间通信的方式。典型的软件架构通信模式如下:
调用 / 返回模式
异步消息通信模式
同步消息通信模式
服务注册、转发、发现模式
广播 / 组播模式
# 1. 调用 / 返回模式
在软件构件之间的通信交互中,一种常见的交互模式就是调用 / 返回模式。
一个客户构件对象的操作方法去调用服务构件对象的操作方法。
当服务构件对象的操作方法执行后,将处理结果返回客户构件对象。

案例:银行服务子系统的软件架构由储蓄账户构件 (SavingsAccount)、支票账户构件 (CheckingAccount)、转账功能构件 (TransferTransactionManager)和取款功能构件 (WithdrawalTransactionManager)所组成。构件对象之间的通信方式如下图所示。

# 5.2 异步消息通信模式
在软件构件的对象交互通信中,生产者构件进程可以独立于消费者构件运行。
一个构件中对象发送一个消息给另一个构件的对象,其发送者不需要等待对方回复,可以继续执行其他操作。

案例:在一个汽车自动泊车控制系统的软件架构中,其中 “运行监控(operationSupervisory)” 构件、“到位传感器(arrivalSensor) 钩件与 “车辆控制(vehicleControl )” 构件之间进行交互通信。

# 5.3 同步消息通信模式
一个构件中对象发送一个消息给另一个构件的对象,需要等待对方回复,才可继续执行其他操作。
若发送消息的构件对象没有收到接收构件对象的回复消息,其进程将会挂起。

案例:在银行服务系统的软件架构中,其中 “ATM 机客户(ATM Client)构件”、 “GUI 用户客户 (GUI UserClient)构件” 与 “银行服务(BankingService)” 构件之间进行消息通信。

# 5.4 服务注册、转发、发现通信模式
服务注册、转发、发现通信模式应用于面向服务的软件架构中,各个服务构件能够分布在多个节点上运行。
这些服务构件在代理构件的协助下能够被客户构件所访问。
代理构件扮演客户构件和服务构件的中介,它使客户构件不需要知道某个服务在哪里提供,而是通过代理构件便能获得服务构件的位置信息。


案例:在基于 Web 服务实现的软件架构中,Web 服务代理者使用统一描述、发现、集成框架 (Universal Description, Discovery and Integration,UDDI) 为客户端提供一种在 Web 上动态发现服务的机制。

# 5.5 广播 / 组播通信模式
广播 / 组播消息通信模式适合于分布式应用,将一个构件消息同时发送到多个构件处理。

案例:一个视频监控跟踪系统有三个卡口视频监控跟踪构件(videoTrace1\videoTrace2\ videoTrace3)、视频监控事件服务(alarmHandingService)构件、视频监测构件 (eventMonitor)组成。它们之间的通信交互关系如下图所示。

# 软件架构事务模式
软件架构事务模式关注构件之间的事务处理,以确保业务数据完整性。典型的软件架构事务模式如下:
两阶段提交协议模式
复合事务模式
长事务模式
# 1. 两阶段提交协议模式
两阶段提交协议模式用于分布式系统中原子事务处理,即确保事务所封装的服务请求操作是不可分割的,它们要么都完成,要么都取消。

在两阶段提交协议模式中,通过一个提交协调构件 (commitCoordinator) 与多个服务构件进行通信协调,实现事务处理。
案例:在从银行 A 的一个账户转账到银行 B 的一个账户中,可以采用两阶段提交协议模式实现转账事务处理,以确保银行数据的一致性。

# 5.2 复合事务模式
在复杂业务处理中,当一个事务可以被分解为若干更小的、独立的处理单元时,这种事务就是复合事务。
例:一个旅游团的出行预订业务,由机票预订、酒店预订和租车预订组成。这些构件服务之间的事务通信关系如下图模型所示。

# 5.3 长事务模式
在业务处理中,若需要用户参与决策操作,则会出现较长时间的数据资源锁定处理,这样的事务称为长事务。
例一个航班预订功能由 “航班 1 预订”、“航班 2 预订”、“航班 3 预订” 等功能构件协作完成,它们之间的事务通信关系如下图模型所示。

# 6. 软件建模详细设计
(1)了解软件建模详细设计的目标、原则、内容;
(2)学握类图的高级建模设计方法;
(3)掌握顺序图和通信图的高级建模设计方法;
(4) 掌握状态机图的高级建模设计方法;
(5) 掌握构件图、部署图、包图的高级建模设计方法;
# UML 软件静态结构视图建模
# 类的聚合关系细分
专属聚合:依赖性、传递性、非对称性、固定性
从属聚合:依赖性、传递性、非对称性
拥有聚合:传递性、非对称性
成员聚合:四个性质都不存在,仅仅是将一组对象组合在一起
# 实现继承
拓展继承:子类组合来自超类的特征,并增加新的特征
限制继承:子类组合来自超类的特征,并重载部分继承来的特征
方便继承:某些类之间具有一定相似的实现,但它们之间不存在泛化关系,即没有概念上的分类关系。方便继承是指将它们中一个类作为其它类的超类。
# 高级类图建模
可见性
导出信息
限定关联
关联类与具体化类
# 接口与抽象类
接口用于定义一个类或者构件的功能操作函数集。
如果接口使用构造型标签表示,实现关系线是一条末端带有空心三角的虚线,箭头指向接口,虚线上可以加上构造型关键字《implement》。
抽象类指不具有实例的类,它通常作为父类,不创建实例对象。抽象类的子类可以实例化。
抽象类一般至少有一个抽象操作。
抽象类的作用是为其子类描述它们的公共属性和行为。
UML 采用斜体表示抽象类的名称,也可以可使用 {abstract} 约束来表示。
# 类内聚与耦合
类耦合的种类:
类之间 6 种关系的耦合强度依次增强:依赖 < 关联 < 聚合 < 组合 < 继承 < 实现
# 软件建模详细设计原则
# 6.1 开闭原则
软件实体(类、构件等)应该对功能扩展具有开放性,对代码修改具有封闭性。当应用需求改变时,在不修改软件实体源代码的前提下,就可以扩展模块的功能,使其满足新的需求。
示例:
定义一个抽象类 Shape ,并让具体的形状类(如 Circle 、 Rectangle )继承它。当需要添加新的形状时,只需创建新的类,而不需要修改现有代码。
abstract class Shape { | |
public abstract void draw(); | |
} | |
class Circle extends Shape { | |
@Override | |
public void draw() { | |
System.out.println("Drawing Circle"); | |
} | |
} | |
class Rectangle extends Shape { | |
@Override | |
public void draw() { | |
System.out.println("Drawing Rectangle"); | |
} | |
} | |
// 新增三角形,无需修改现有代码 | |
class Triangle extends Shape { | |
@Override | |
public void draw() { | |
System.out.println("Drawing Triangle"); | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Shape circle = new Circle(); | |
Shape rectangle = new Rectangle(); | |
Shape triangle = new Triangle(); | |
circle.draw(); | |
rectangle.draw(); | |
triangle.draw(); | |
} | |
} |
# 6.2 里氏替换原则
子类可以扩展基类的功能,但不能改变基类原有的功能。子类在继承基类时,除了添加新的方法且完成新增功能外,不要重写基类的方法代码。子类必须遵守基类与外部类之间的隐含约定。
原则:子类可以扩展基类的功能,但不能改变基类原有的功能。
示例:
定义一个基类 Bird ,其中有一个方法 fly() 。子类 Sparrow 继承 Bird 并实现了 fly() 方法。如果有一个子类 Penguin ,它不能飞行,那么 Penguin 不应该继承 Bird 。
class Bird { | |
public void fly() { | |
System.out.println("Bird is flying"); | |
} | |
} | |
class Sparrow extends Bird { | |
@Override | |
public void fly() { | |
System.out.println("Sparrow is flying"); | |
} | |
} | |
// 企鹅不会飞,不应该继承 Bird | |
class Penguin { | |
public void swim() { | |
System.out.println("Penguin is swimming"); | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Bird sparrow = new Sparrow(); | |
sparrow.fly(); | |
Penguin penguin = new Penguin(); | |
penguin.swim(); | |
} | |
} |
# 6.3 依赖倒置原则
基于抽象类编程,不依赖具体类编程。面向接口编程,不要面向实现编程。
原则:基于抽象编程,不依赖具体实现。
示例:
定义一个接口 Switchable , Light 实现该接口。 Switch 类依赖 Switchable 接口,而不是具体的 Light 类。
interface Switchable { | |
void turnOn(); | |
void turnOff(); | |
} | |
class Light implements Switchable { | |
@Override | |
public void turnOn() { | |
System.out.println("Light is on"); | |
} | |
@Override | |
public void turnOff() { | |
System.out.println("Light is off"); | |
} | |
} | |
class Switch { | |
private Switchable device; | |
public Switch(Switchable device) { | |
this.device = device; | |
} | |
public void operate() { | |
device.turnOn(); | |
device.turnOff(); | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Switchable light = new Light(); | |
Switch switchButton = new Switch(light); | |
switchButton.operate(); | |
} | |
} |
# 6.4 接口分离原则
一个构件对外应提供不同服务的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的构件去调用,避免客户端依赖不必要的接口方法。提供者构件应该为每个不同访问构件类型提供一个特定的接口。
原则:一个构件应提供专用的接口,而不是一个大而全的接口。
示例:
将打印、扫描和传真功能分离成不同的接口。
interface Printer { | |
void print(); | |
} | |
interface Scanner { | |
void scan(); | |
} | |
interface Fax { | |
void fax(); | |
} | |
class MultiFunctionDevice implements Printer, Scanner, Fax { | |
@Override | |
public void print() { | |
System.out.println("Printing"); | |
} | |
@Override | |
public void scan() { | |
System.out.println("Scanning"); | |
} | |
@Override | |
public void fax() { | |
System.out.println("Faxing"); | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
MultiFunctionDevice mfd = new MultiFunctionDevice(); | |
mfd.print(); | |
mfd.scan(); | |
mfd.fax(); | |
} | |
} |
# 6.5 单一职责原则
一个类应该有且仅有一个功能职责,否则该类应该被拆分。单一职责原则的核心就是控制类的粒度大小,将对象解耦,提高其内聚性。
原则:一个类应该有且仅有一个职责。
示例:
将用户信息存储和用户认证分离到不同的类中。
class User { | |
private String name; | |
private String email; | |
public User(String name, String email) { | |
this.name = name; | |
this.email = email; | |
} | |
public String getName() { | |
return name; | |
} | |
public String getEmail() { | |
return email; | |
} | |
} | |
class UserAuthenticator { | |
public boolean authenticate(User user, String password) { | |
// 认证逻辑 | |
System.out.println("Authenticating user: " + user.getName()); | |
return true; // 假设认证成功 | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
User user = new User("John", "[email protected]"); | |
UserAuthenticator authenticator = new UserAuthenticator(); | |
authenticator.authenticate(user, "password123"); | |
} | |
} |
# 6.6 最少知识原则
迪米特法则的定义是:只与你的朋友交谈,不跟 “陌生人” 说话。在程序设计中,如果两个软件实体没有直接关系,那么就不要直接调用,可以通过第三方转发该调用。
原则:只与直接的朋友交互,避免与陌生人直接交互。
示例:Customer 类通过 Order 提供的接口访问订单信息,而不是直接访问 Order 的内部细节。
class Order { | |
private String[] items; | |
public Order(String[] items) { | |
this.items = items; | |
} | |
public String[] getItems() { | |
return items; | |
} | |
} | |
class Customer { | |
private Order order; | |
public Customer(Order order) { | |
this.order = order; | |
} | |
public void printOrderItems() { | |
String[] items = order.getItems(); | |
for (String item : items) { | |
System.out.println(item); | |
} | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Order order = new Order(new String[]{"item1", "item2"}); | |
Customer customer = new Customer(order); | |
customer.printOrderItems(); | |
} | |
} |
# 6.7 高内聚原则

原则:一个模块或类应该专注于完成一个单一的任务或功能,其内部的各个部分应紧密相关。
示例:
假设有一个 OrderProcessor 类,它负责处理订单。如果我们将订单验证、订单保存和订单通知的功能都放在这个类中,会导致低内聚。我们可以将这些功能拆分到不同的类中,使每个类只专注于一个任务。
// 高内聚的类设计 | |
class OrderValidator { | |
public boolean validate(Order order) { | |
// 验证订单逻辑 | |
System.out.println("Validating order: " + order.getId()); | |
return true; // 假设验证成功 | |
} | |
} | |
class OrderSaver { | |
public void save(Order order) { | |
// 保存订单逻辑 | |
System.out.println("Saving order: " + order.getId()); | |
} | |
} | |
class OrderNotifier { | |
public void notifyCustomer(Order order) { | |
// 通知客户逻辑 | |
System.out.println("Notifying customer for order: " + order.getId()); | |
} | |
} | |
class OrderProcessor { | |
private OrderValidator validator; | |
private OrderSaver saver; | |
private OrderNotifier notifier; | |
public OrderProcessor(OrderValidator validator, OrderSaver saver, OrderNotifier notifier) { | |
this.validator = validator; | |
this.saver = saver; | |
this.notifier = notifier; | |
} | |
public void process(Order order) { | |
if (validator.validate(order)) { | |
saver.save(order); | |
notifier.notifyCustomer(order); | |
} | |
} | |
} | |
class Order { | |
private String id; | |
public Order(String id) { | |
this.id = id; | |
} | |
public String getId() { | |
return id; | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Order order = new Order("12345"); | |
OrderValidator validator = new OrderValidator(); | |
OrderSaver saver = new OrderSaver(); | |
OrderNotifier notifier = new OrderNotifier(); | |
OrderProcessor processor = new OrderProcessor(validator, saver, notifier); | |
processor.process(order); | |
} | |
} |
# 6.8 松耦合原则

原则:模块或类之间的依赖应尽量减少,一个模块的变化不应影响其他模块。
示例:
通过依赖注入(Dependency Injection)实现松耦合。 OrderProcessor 依赖于抽象的 Validator 和 Saver 接口,而不是具体的实现类。
// 松耦合的类设计 | |
interface Validator { | |
boolean validate(Order order); | |
} | |
interface Saver { | |
void save(Order order); | |
} | |
class OrderValidator implements Validator { | |
@Override | |
public boolean validate(Order order) { | |
System.out.println("Validating order: " + order.getId()); | |
return true; | |
} | |
} | |
class OrderSaver implements Saver { | |
@Override | |
public void save(Order order) { | |
System.out.println("Saving order: " + order.getId()); | |
} | |
} | |
class OrderProcessor { | |
private Validator validator; | |
private Saver saver; | |
public OrderProcessor(Validator validator, Saver saver) { | |
this.validator = validator; | |
this.saver = saver; | |
} | |
public void process(Order order) { | |
if (validator.validate(order)) { | |
saver.save(order); | |
} | |
} | |
} | |
class Order { | |
private String id; | |
public Order(String id) { | |
this.id = id; | |
} | |
public String getId() { | |
return id; | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Order order = new Order("12345"); | |
Validator validator = new OrderValidator(); | |
Saver saver = new OrderSaver(); | |
OrderProcessor processor = new OrderProcessor(validator, saver); | |
processor.process(order); | |
} | |
} |
# 6.9 可重用原则

原则:设计模块或类时,应尽量使其功能通用化,以便在不同的上下文中重复使用。
示例:
设计一个通用的 Logger 类,可以在不同的模块中重复使用。
// 可重用的类设计 | |
class Logger { | |
public void log(String message) { | |
System.out.println("[LOG] " + message); | |
} | |
} | |
class OrderService { | |
private Logger logger; | |
public OrderService(Logger logger) { | |
this.logger = logger; | |
} | |
public void placeOrder(Order order) { | |
logger.log("Placing order: " + order.getId()); | |
// 订单处理逻辑 | |
} | |
} | |
class PaymentService { | |
private Logger logger; | |
public PaymentService(Logger logger) { | |
this.logger = logger; | |
} | |
public void processPayment(Order order) { | |
logger.log("Processing payment for order: " + order.getId()); | |
// 支付处理逻辑 | |
} | |
} | |
class Order { | |
private String id; | |
public Order(String id) { | |
this.id = id; | |
} | |
public String getId() { | |
return id; | |
} | |
} | |
public class Main { | |
public static void main(String[] args) { | |
Logger logger = new Logger(); | |
OrderService orderService = new OrderService(logger); | |
PaymentService paymentService = new PaymentService(logger); | |
Order order = new Order("12345"); | |
orderService.placeOrder(order); | |
paymentService.processPayment(order); | |
} | |
} |
# 设计模式
# 创建型模式类型
# 单例模式(Singleton Pattern)
饿汉式
- 在单例类被加载时候,就实例化一个对象交给自己的引用。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}}懒汉式
- 在访问实例对象时才实例化对象。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}return instance;
}}
# 工厂模式 (Factory Pattern)
工厂模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类。
假设我们有一个 Shape 接口和多个形状类(如 Circle 、 Square ),我们可以使用工厂模式来创建这些形状对象。
// 形状接口 | |
interface Shape { | |
void draw(); | |
} | |
// 具体形状类 | |
class Circle implements Shape { | |
@Override | |
public void draw() { | |
System.out.println("Drawing Circle"); | |
} | |
} | |
class Square implements Shape { | |
@Override | |
public void draw() { | |
System.out.println("Drawing Square"); | |
} | |
} | |
// 形状工厂类 | |
class ShapeFactory { | |
public Shape getShape(String shapeType) { | |
if (shapeType == null) { | |
return null; | |
} | |
if (shapeType.equalsIgnoreCase("CIRCLE")) { | |
return new Circle(); | |
} else if (shapeType.equalsIgnoreCase("SQUARE")) { | |
return new Square(); | |
} | |
return null; | |
} | |
} | |
// 客户端代码 | |
public class FactoryPatternDemo { | |
public static void main(String[] args) { | |
ShapeFactory shapeFactory = new ShapeFactory(); | |
// 创建 Circle 对象 | |
Shape circle = shapeFactory.getShape("CIRCLE"); | |
circle.draw(); | |
// 创建 Square 对象 | |
Shape square = shapeFactory.getShape("SQUARE"); | |
square.draw(); | |
} | |
} |
抽象工厂模式 (Abstract Factory Pattern)
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
假设我们有两种产品族: Color 和 Shape ,我们可以使用抽象工厂模式来创建这些产品。
// 颜色接口 | |
interface Color { | |
void fill(); | |
} | |
// 具体颜色类 | |
class Red implements Color { | |
@Override | |
public void fill() { | |
System.out.println("Filling with Red"); | |
} | |
} | |
class Blue implements Color { | |
@Override | |
public void fill() { | |
System.out.println("Filling with Blue"); | |
} | |
} | |
// 形状接口 | |
interface Shape { | |
void draw(); | |
} | |
// 具体形状类 | |
class Circle implements Shape { | |
@Override | |
public void draw() { | |
System.out.println("Drawing Circle"); | |
} | |
} | |
class Square implements Shape { | |
@Override | |
public void draw() { | |
System.out.println("Drawing Square"); | |
} | |
} | |
// 抽象工厂接口 | |
abstract class AbstractFactory { | |
abstract Color getColor(String color); | |
abstract Shape getShape(String shape); | |
} | |
// 颜色工厂 | |
class ColorFactory extends AbstractFactory { | |
@Override | |
public Color getColor(String color) { | |
if (color == null) { | |
return null; | |
} | |
if (color.equalsIgnoreCase("RED")) { | |
return new Red(); | |
} else if (color.equalsIgnoreCase("BLUE")) { | |
return new Blue(); | |
} | |
return null; | |
} | |
@Override | |
public Shape getShape(String shape) { | |
return null; | |
} | |
} | |
// 形状工厂 | |
class ShapeFactory extends AbstractFactory { | |
@Override | |
public Color getColor(String color) { | |
return null; | |
} | |
@Override | |
public Shape getShape(String shape) { | |
if (shape == null) { | |
return null; | |
} | |
if (shape.equalsIgnoreCase("CIRCLE")) { | |
return new Circle(); | |
} else if (shape.equalsIgnoreCase("SQUARE")) { | |
return new Square(); | |
} | |
return null; | |
} | |
} | |
// 工厂生成器 | |
class FactoryProducer { | |
public static AbstractFactory getFactory(String choice) { | |
if (choice.equalsIgnoreCase("COLOR")) { | |
return new ColorFactory(); | |
} else if (choice.equalsIgnoreCase("SHAPE")) { | |
return new ShapeFactory(); | |
} | |
return null; | |
} | |
} | |
// 客户端代码 | |
public class AbstractFactoryPatternDemo { | |
public static void main(String[] args) { | |
// 获取颜色工厂 | |
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); | |
// 获取颜色对象 | |
Color red = colorFactory.getColor("RED"); | |
red.fill(); | |
// 获取形状工厂 | |
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE"); | |
// 获取形状对象 | |
Shape circle = shapeFactory.getShape("CIRCLE"); | |
circle.draw(); | |
} | |
} |
建造者模式(Builder Pattern)
建造者模式将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
原型模式(Prototype Pattern)
# 结构型模式类型
# 适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

以下是一个适配器模式的例子:
假设我们有一个旧的音频播放器类 OldAudioPlayer ,它只能播放 MP3 文件。现在我们有一个新的音频播放器类 NewAudioPlayer ,它可以播放 MP4 和 VLC 文件。我们希望在不修改现有代码的情况下,让旧的音频播放器也能播放 MP4 和 VLC 文件。
// 旧的音频播放器接口 | |
interface OldAudioPlayer { | |
void playMp3(String fileName); | |
} | |
// 新的音频播放器接口 | |
interface NewAudioPlayer { | |
void playMp4(String fileName); | |
void playVlc(String fileName); | |
} | |
// 旧的音频播放器实现 | |
class OldMp3Player implements OldAudioPlayer { | |
@Override | |
public void playMp3(String fileName) { | |
System.out.println("Playing MP3 file: " + fileName); | |
} | |
} | |
// 新的音频播放器实现 | |
class NewAdvancedPlayer implements NewAudioPlayer { | |
@Override | |
public void playMp4(String fileName) { | |
System.out.println("Playing MP4 file: " + fileName); | |
} | |
@Override | |
public void playVlc(String fileName) { | |
System.out.println("Playing VLC file: " + fileName); | |
} | |
} | |
// 适配器类 | |
class AudioAdapter implements OldAudioPlayer { | |
private NewAudioPlayer newAudioPlayer; | |
public AudioAdapter(NewAudioPlayer newAudioPlayer) { | |
this.newAudioPlayer = newAudioPlayer; | |
} | |
@Override | |
public void playMp3(String fileName) { | |
System.out.println("Adapter converts MP3 to MP4"); | |
newAudioPlayer.playMp4(fileName); | |
} | |
public void playMp4(String fileName) { | |
newAudioPlayer.playMp4(fileName); | |
} | |
public void playVlc(String fileName) { | |
newAudioPlayer.playVlc(fileName); | |
} | |
} | |
// 客户端代码 | |
public class AdapterPatternDemo { | |
public static void main(String[] args) { | |
OldAudioPlayer oldAudioPlayer = new OldMp3Player(); | |
oldAudioPlayer.playMp3("song.mp3"); | |
NewAudioPlayer newAudioPlayer = new NewAdvancedPlayer(); | |
OldAudioPlayer audioAdapter = new AudioAdapter(newAudioPlayer); | |
// 使用适配器播放 MP4 文件 | |
audioAdapter.playMp4("movie.mp4"); | |
// 使用适配器播放 VLC 文件 | |
audioAdapter.playVlc("video.vlc"); | |
// 使用适配器播放 MP3 文件 | |
audioAdapter.playMp3("song.mp3"); | |
} | |
} |
OldAudioPlayer:旧的音频播放器接口,只能播放 MP3 文件。
NewAudioPlayer:新的音频播放器接口,可以播放 MP4 和 VLC 文件。
OldMp3Player:旧的音频播放器实现类。
NewAdvancedPlayer:新的音频播放器实现类。
AudioAdapter:适配器类,实现了
OldAudioPlayer接口,并在内部使用NewAudioPlayer来播放 MP4 和 VLC 文件。
适配器模式通过创建一个适配器类,将不兼容的接口转换为客户端所期望的接口,从而使得原本由于接口不兼容而不能一起工作的类可以一起工作。在这个例子中, AudioAdapter 类使得旧的音频播放器能够播放 MP4 和 VLC 文件。
# 桥接模式 (Bridge Pattern)
桥接模式的核心在于将抽象(Abstraction)与实现(Implementation)分离,使它们可以独立变化。抽象部分定义了高层控制逻辑,而实现部分则负责底层操作。
当需要避免在抽象和实现之间形成固定的绑定关系时。
当抽象和实现都需要通过子类化进行扩展时。
当需要对抽象部分和实现部分进行独立的修改时。
# 代码
// 实现类接口:颜色 | |
interface Color { | |
String fill(); | |
} | |
// 具体实现类:红色 | |
class Red implements Color { | |
@Override | |
public String fill() { | |
return "Red"; | |
} | |
} | |
// 具体实现类:蓝色 | |
class Blue implements Color { | |
@Override | |
public String fill() { | |
return "Blue"; | |
} | |
} | |
// 抽象类:形状 | |
abstract class Shape { | |
protected Color color; | |
public Shape(Color color) { | |
this.color = color; | |
} | |
public abstract String draw(); | |
} | |
// 扩展抽象类:圆形 | |
class Circle extends Shape { | |
public Circle(Color color) { | |
super(color); | |
} | |
@Override | |
public String draw() { | |
return "Circle filled with " + color.fill(); | |
} | |
} | |
// 扩展抽象类:矩形 | |
class Rectangle extends Shape { | |
public Rectangle(Color color) { | |
super(color); | |
} | |
@Override | |
public String draw() { | |
return "Rectangle filled with " + color.fill(); | |
} | |
} | |
// 客户端代码 | |
public class BridgePatternDemo { | |
public static void main(String[] args) { | |
// 创建颜色对象 | |
Color red = new Red(); | |
Color blue = new Blue(); | |
// 创建形状对象,并组合颜色 | |
Shape redCircle = new Circle(red); | |
Shape blueRectangle = new Rectangle(blue); | |
// 绘制形状 | |
System.out.println(redCircle.draw()); // 输出: Circle filled with Red | |
System.out.println(blueRectangle.draw()); // 输出: Rectangle filled with Blue | |
} | |
} |
装饰器模式(Decorator Pattern)
外观模式(Facade Pattern)
组合模式(Composite Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
# 行为型模式类型
# 责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
观察者模式(Observer Pattern)
备忘录模式(Memento Pattern)
# 7. 用户界面设计
(1)了解信息系统用户界面的组成、设计原则、设计内容、设计过程;
(2)掌握 Web 系统用户界面的设计要素、建模设计方法、界面逻辑表达;
(3)掌握移动 App 用户界面的设计要素、建模设计方法、界面逻辑表达。
web 总体页面结构的设计
线性结构
分层结构
网络结构
页面布局设计
一栏式页面布局
两栏式页面布局
三栏式页面布局
页面导航设计
导航结构
水平栏目导航
垂直栏目导航
混合栏目导航
导航机制
导航菜单
面包屑导航连接
tab 导航标签
导航语义
导航语义是指用户完成系统一个功能操作的页面导航流程。需通过特定的名称或符号来传达导航组件的功能和目的。
在登录页面中,若用户忘记密码,可以通过点击 “密码找回” 链接重置用户密码。
其 “密码找回” 链接导航语义的流程为:“在登录页面中点取 “密码找回” 链接 -> 在密码找回页面中输入用户账户和邮箱信息 -> 系统发送重置密码邮件 -> 在邮件界面中点取重置页面链接 ->打开重置密码页面 -> 在重置密码页面中输入新密码和确认密码 -> 系统显示密码修改成功操作页面”。
App
页面导航
底部标签导航
顶部 + 底部双标签导航
舵式标签导航
宫格导航
列表导航
抽屉式导航
轮播导航
交互设计
![]()
# 重点问题
# 1. 分析下面设计类图如何解决新能源汽车的发动机接口适配?给出 Java 程序实现该设计功能。

1. 解决新能源汽车发动机接口适配问题
适配器模式通过以下方式解决接口适配问题:
统一接口:通过
Motor接口定义统一的drive()方法,客户端只需要调用drive()方法即可。适配不兼容的类:
ElectricAdapter和OpticalAdapter分别将ElectricMotor和OpticalMotor的特定方法(electricDrive()和opticalDrive())适配到Motor接口的drive()方法。灵活扩展:如果需要支持新的发动机类型,只需添加新的适配器类,而不需要修改客户端代码。
// 目标接口 | |
interface Motor { | |
void drive(); | |
} | |
// 适配者类 1 | |
class ElectricMotor { | |
public void electricDrive() { | |
System.out.println("Electric motor is driving."); | |
} | |
} | |
// 适配者类 2 | |
class OpticalMotor { | |
public void opticalDrive() { | |
System.out.println("Optical motor is driving."); | |
} | |
} | |
// 适配器类 1:适配 ElectricMotor 到 Motor 接口 | |
class ElectricAdapter implements Motor { | |
private ElectricMotor electricMotor; | |
public ElectricAdapter(ElectricMotor electricMotor) { | |
this.electricMotor = electricMotor; | |
} | |
@Override | |
public void drive() { | |
electricMotor.electricDrive(); | |
} | |
} | |
// 适配器类 2:适配 OpticalMotor 到 Motor 接口 | |
class OpticalAdapter implements Motor { | |
private OpticalMotor opticalMotor; | |
public OpticalAdapter(OpticalMotor opticalMotor) { | |
this.opticalMotor = opticalMotor; | |
} | |
@Override | |
public void drive() { | |
opticalMotor.opticalDrive(); | |
} | |
} | |
// 客户端 | |
public class MotorAdapterTest { | |
public static void main(String[] args) { | |
// 创建适配者对象 | |
ElectricMotor electricMotor = new ElectricMotor(); | |
OpticalMotor opticalMotor = new OpticalMotor(); | |
// 创建适配器对象 | |
Motor electricAdapter = new ElectricAdapter(electricMotor); | |
Motor opticalAdapter = new OpticalAdapter(opticalMotor); | |
// 使用适配器驱动发动机 | |
electricAdapter.drive(); // 输出: Electric motor is driving. | |
opticalAdapter.drive(); // 输出: Optical motor is driving. | |
} | |
} |
# 2. 针对如下民政服务系统的婚姻登记功能设计类图,采用饿汉式单例模式实现该功能的 Java 程序编写,并在主程序中输出消息反馈。

// 单例类:婚姻登记 | |
class MarriageRegister { | |
// 静态私有实例,类加载时创建 | |
private static final MarriageRegister instance = new MarriageRegister(); | |
// 私有构造函数,防止外部实例化 | |
private MarriageRegister() {} | |
// 静态公有方法,用于获取单例实例 | |
public static MarriageRegister getInstance() { | |
return instance; | |
} | |
// 公有方法,显示婚姻登记功能的消息 | |
public void showMessage() { | |
System.out.println("婚姻登记功能已启动。"); | |
} | |
} | |
// 客户端 | |
public class Client { | |
public static void main(String[] args) { | |
// 获取单例实例 | |
MarriageRegister register = MarriageRegister.getInstance(); | |
// 调用单例实例的方法 | |
register.showMessage(); // 输出:婚姻登记功能已启动。 | |
} | |
} |
# 7.3 分析如下请假条审批模块功能类图如何应用责任链模式设计?如何编写 Java 程序。

// 抽象处理者 | |
abstract class Leader { | |
protected Leader next; | |
public void setNext(Leader next) { | |
this.next = next; | |
} | |
public Leader getNext() { | |
return next; | |
} | |
public abstract void handleRequest(int leaveDays); | |
} | |
// 具体处理者:班主任 | |
class ClassAdviser extends Leader { | |
@Override | |
public void handleRequest(int leaveDays) { | |
if (leaveDays <= 2) { | |
System.out.println("班主任批准了 " + leaveDays + " 天的请假。"); | |
} else if (next != null) { | |
next.handleRequest(leaveDays); | |
} else { | |
System.out.println("请假天数过长,无法批准。"); | |
} | |
} | |
} | |
// 具体处理者:系主任 | |
class DepartmentHead extends Leader { | |
@Override | |
public void handleRequest(int leaveDays) { | |
if (leaveDays <= 5) { | |
System.out.println("系主任批准了 " + leaveDays + " 天的请假。"); | |
} else if (next != null) { | |
next.handleRequest(leaveDays); | |
} else { | |
System.out.println("请假天数过长,无法批准。"); | |
} | |
} | |
} | |
// 具体处理者:院长 | |
class Dean extends Leader { | |
@Override | |
public void handleRequest(int leaveDays) { | |
if (leaveDays <= 10) { | |
System.out.println("院长批准了 " + leaveDays + " 天的请假。"); | |
} else { | |
System.out.println("请假天数过长,无法批准。"); | |
} | |
} | |
} | |
// 客户端 | |
public class LeaveApprovalTest { | |
public static void main(String[] args) { | |
// 创建处理者 | |
Leader teacher1 = new ClassAdviser(); | |
Leader teacher2 = new DepartmentHead(); | |
Leader teacher3 = new Dean(); | |
// 设置责任链 | |
teacher1.setNext(teacher2); | |
teacher2.setNext(teacher3); | |
// 处理请假请求 | |
teacher1.handleRequest(1); // 班主任批准了 1 天的请假。 | |
teacher1.handleRequest(4); // 系主任批准了 4 天的请假。 | |
teacher1.handleRequest(8); // 院长批准了 8 天的请假。 | |
teacher1.handleRequest(12); // 请假天数过长,无法批准。 | |
} | |
} |
# 7.4 分析说明以下包图如何建模描述系统的软件架构?

该系统包括多个层次,包括用户层 user、表示层 presentation layer、外部系统 external system、服务层 services layer、商业层 business layer、数据层 data layer、数据资源 data source、外部服务 external services 以及附加层 cross cutting;
user 用户层与表示层连接,表示层 presentation layer 中含有 user interface 接口和 presentation logic 表现逻辑;
表示层又与商业层和附加层连接;
外部系统 external system 与服务层连接;
服务层与商业层和附加层连接;
商业层 business layer 中含有 application facade 应用界面;
该应用界面构件与商业层中的其他构件连接,包括 business workflow 工作流、business components 工作组件、business entities 业务实体;
附加层 cross cutting 包括 security 安全组件、operational management 工作管理、communication 通信组件;
业务层与数据层 data layer 连接;
data layer 层包括 data access 数据加工、service agents 服务,并与附加层连接;
数据层还与 data source 数据资源连接,并于 external services 外部服务连接。
# 7.5 分析以下支付模块的设计类图,该设计遵循了哪些设计原则?

开闭原则:支持扩展新的支付方式,而不需要修改现有代码。
依赖倒置原则:高层模块依赖于抽象(
Payment接口),而不是具体的实现。单一职责原则:每个类只负责一个功能。
接口隔离原则:接口只定义了必要的方法。
# 7.6 以下类模块(客户数据图形分析)设计违背什么设计原则?会带来什么问题?请给出完善后的设计类图。

# 违背的设计原则
单一职责原则(SRP):
CustomerDataChart类同时负责数据访问、数据处理和图表展示,职责过多。如果数据库连接方式、数据查找逻辑或图表展示方式发生变化,都需要修改
CustomerDataChart类,导致代码难以维护。
高内聚低耦合原则:
由于职责混杂,
CustomerDataChart类的内聚性较低,耦合性较高。修改一个功能可能会影响其他功能,增加了代码的脆弱性。
# 带来的问题
代码难以维护:
- 由于职责混杂,修改一个功能可能会影响其他功能,增加了维护成本。
可复用性差:
- 数据访问和图表展示逻辑耦合在一起,无法单独复用。
测试困难:
- 由于职责混杂,单元测试需要覆盖多个功能,增加了测试的复杂性。
扩展性差:
- 如果需要支持新的图表类型或数据源,需要修改
CustomerDataChart类,违反了开闭原则。
- 如果需要支持新的图表类型或数据源,需要修改
# 7.7 以下客户功能模块类图违背什么设计原则?存在问题?请给出完善后的设计类图?

# 违背的设计原则
接口隔离原则(Interface Segregation Principle, ISP):
IClient接口定义了多个方法,但并不是所有的客户端都需要实现所有这些方法。例如,某些客户端可能只需要
send()和receive(),而不需要connect()和disconnect()。强制实现不需要的方法会导致接口臃肿,违反接口隔离原则。
单一职责原则(Single Responsibility Principle, SRP):
IClient接口承担了过多的职责,包括连接管理、数据发送和接收。这导致接口的职责不够单一,增加了实现的复杂性。
# 存在的问题
接口臃肿:
IClient接口包含了多个方法,导致实现类必须实现所有方法,即使某些方法并不需要。
灵活性差:
- 如果某个客户端只需要部分功能(如只发送数据),仍然需要实现所有方法,增加了不必要的复杂性。
可维护性低:
- 修改接口会影响所有实现类,即使这些实现类并不使用被修改的方法。
# 8. 在 QQ、银行转账系统架构设计中,分别选择 CAP 模型的哪个方案设计实现?

QQ:AP
银行:CP
