软件设计与体系结构B复习


1~8

各种性能指标的定义及如何到达各种性能指标的方法

  • 吞吐量 (Throughput)
    定义:单位时间内成功地传送数据的数量
    实现:Average 平均,Peak 峰值
    许多系统具有低平均但高峰值吞吐量的需求

  • 响应时间(Response Time)
    定义:应用程序在处理请求时显示延迟的时间
    实现:Guaranteed time 最大响应时间 Average time 平均响应时间
    95%的响应在4秒以内,全部在10秒之内

  • 最后期限(Deadlines)
    定义:有些事情必须在指定的时间之前完成
    实现:最后期限通常与IT系统中的批处理作业相关。

有哪些常见架构风格

1)管道和过滤器(Pipe and Filter)

  • 管道-过滤器模式的体系结构是面向数据流的软件体系结构。
  • 它最典型的应用是在编译系统。
  • 一个普通的编译系统包括词法分析器,语法分析器,语义分析与中间代码生成器,优化器,目标代码生成器等一系列对源程序进行处理的过程。
  • 人们可以将编译系统看作一系列过滤器的连接体,按照管道-过滤器的体系结构进行设计。
  • 此外,这种体系结构在其它一些领域也有广泛的应用。因此它成为软件工程和软件开发中的一个突出的研究领域。
  • 举例:unix的shell脚本、传统编译器

2)面向对象(Object-Oriented)

  • 适用于主要问题是识别和保护信息的相关主体。 数据代理和它们相关的操作封装在一个抽象数据类型里面。
  • 举例:java,c#开发的系统

3)隐式调用(Implicit Invocation)

  • 隐式调用风格的思想是构件不直接调用一个过程,而是触发或广播一个或多个事件。
  • 基于事件的系统中的其它构件中的过程在一个或多个事件中注册,当一个事件被触发,系统自动调用在这个事件中注册的所有过程,这样,一个事件的触发就导致了另一模块中的过程的调用。
  • 支持基于事件的隐式调用的应用系统很多。例如,在编程环境中用于集成各种工具,在数据库管理系统中确保数据的一致性约束,在用户界面系统中管理数据,以及在编辑器中支持语法检查。例如在某系统中,编辑器和变量监视器可以登记相应Debugger的断点事件。当Debugger在断点处停下时,它声明该事件,由系统自动调用处理程序,如编辑程序可以卷屏到断点,变量监视器刷新变量数值。而Debugger本身只声明事件,并不关心哪些过程会启动,也不关心这些过程做什么处理。
  • 举例:数据库管理系统中执行完整性约束(触发器)。
    在用户界面中用于将数据表示与管理该数据的应用程序分离。

4)客户-服务器风格

  • 客户服务器方式(简称C/S方式),为网络边缘的系统中运行的程序之间的一种通信方式。描述的是进程之间服务和被服务的关系,客户是服务请求方,服务器是服务提供方。客户服务器模式是一种分布式系统体系结构。
  • 客户(client)和服务器(server)都是指通信中所涉及的两个应用程序。客户服务器方式描述的是进程之间服务和被服务的关系。这里所说的客户和服务器都指的是计算机进程(软件)。在C/S方式中,请求一方为客户,响应请求一方称为服务器,如果一个服务器在响应客户请求时不能单独完成任务,还可能向其他服务器发出请求,这时,发出请求的服务器就成为另一个服务器的客户。从双方建立联系的方式来看,主动启动通信的应用叫客户,被动等待通信的应用叫服务器。这里最主要的特征就是:客户是服务请求方,服务器是服务提方。
  • 举例:文件服务器、数据库服务器、对象服务器

5)分层风格

  • 把应用的关注点分割为堆栈组(层)。
  • 适用于涉及到分布式的能够分层的组织的类的服务,每层给它的上一层提供服务,同时作为下一层的客户端,只有仔细地从内层选择选择过程,才能用于他们临近的外层。
  • 分层架构的一个重要原则是:每层只能与位于其下方的层发生耦合。分层架构也分为几种:在严格分层架构中,某层只能与直接位于其下方的层发生耦合;而松散分层架构则允许任意上方层与任意下方层发生耦合。由于用户界面层和应用服务通常需要与基础设施打交道,许多系统都是基于松散分层架构的。
  • 举例:分层通信协议、操作系统

6)仓库风格

  • 适用于主要问题是建立、增加和维护复杂信息的主体部分,信息一定要能够用很多种方式操作。经常需要长期的存在。
  • 优点:有效存储大量数据、共享式模式模型、集中式管理
  • 缺点:必须先达成一个数据模型、很难分配数据、数据升级很昂贵
  • 举例:信息系统、编程环境、图形编辑器、人工智能知识基础、逆向工程系统

7)解释程序风格

  • 解释程序是一种语言处理程序,在词法、语法和语义分析方面与编译程序的工作原理基本相同,但在运行用户程序时,它直接执行源程序或源程序的内部形式(中间代码)。因此,解释程序并不产生目标程序,这是它和编译程序的主要区别。
  • 适用于执行 解决方案的最合适的语言 或是 机器不是直接可用的。
  • 举例:编程语言编译器、基于规则的系统、脚本语言

8)过程控制风格

  • 适用于目的是维护特殊过程的输出属性在给定参考值的情形下
  • 举例:实时系统软件用来控制(核电站、汽车巡航控制)

补充内容:
分布式系统(distributed system)是建立在网络之上的软件系统。分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。

架构设计分几个层次

三层系统的分层式结构

三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:

  • 表现层(UI)

  • 业务逻辑层(BLL)

  • 数据访问层(DAL)

    区分层次的目的即为了“高内聚,低耦合”的思想。

  1. 表现层(UI):通俗讲就是展现给用户的界面,即用户在使用一个系统的时候他的所见所得。
  2. 业务逻辑层(BLL):针对具体问题的操作,也可以说是对数据层的操作,对数据业务逻辑处理。
  3. 数据访问层(DAL):该层所做事务直接操作数据库,针对数据的增添、删除、修改、查找等。

在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。

微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或称为领域层)、表示层。

架构师需要的核心技能是什么

  • 团队之间的交流 Liaison with stakeholders
  • 技术知识 Technology knowledge
  • 软件工程学 Software engineering
  • 风险管理 Risk managements

什么是软件架构(好几种定义,但是主要点是结构,元素,关系,接口)

  • 软件架构(software architecture)是一系列相关的抽象模式,用于指导大型软件系统各个方面的设计。
  • 软件架构是一个系统的草图。

(PPT ch1-ch8 slide 3- 7)

  • It’s about software design
    软件架构是软件设计过程的一部分。
    All architecture is software design, but not all design is software architecture
    所有的架构都是软件设计,但不是所有的设计都是软件架构
    Part of the design process
    设计过程的一部分
  • Simply, architecture focuses on ‘issues that will be difficult/impossible to change once the system is built’
    简单地说,架构关注的是“一旦构建系统,就很难/不可能更改的问题”
    Quality attributes like security, performance
    质量属性,如安全性、性能
    Non-functional requirements like cost, deployment hardware
    非功能性需求,如成本、部署硬件

“Architecture is the fundamental organization of a system, embodied in its components, their relationships to each other and the environment, and the principles governing its design and evolution.”
体系结构是一个系统的基本组织,体现在它的组件、它们彼此之间的关系和环境中,以及控制它的设计和演进的原则中。

“The software architecture of a program or computing system is the structure or structures of the system, which comprise software elements, the externally visible properties of those elements, and the relationships among them.”
程序或计算系统的软件架构是 系统的一个或多个结构,
它包括 软件元素、这些元素的外部可见属性 和 它们之间的关系。

软件架构主要关注那些问题

‘issues that will be difficult/impossible to change once the system is built’
“一旦系统建立后就很难或是不可能改变的问题”:
Quality attributes like security, performance
质量属性,例如 安全性 , 性能
Non-functional requirements like cost, deployment hardware
非功能性需求,像开销, 硬件配置

什么是架构风格

软件体系结构风格是描述某一特定 应用领域 中 系统组织方式 的 惯用模式。

体系结构风格定义一个系统家族,即一个体系结构定义一个词汇表和一组约束。词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的。

什么是架构视图

架构视图:

  • 对于从 某一视角 或 某一点 上看到的系统所做的 简化描述 ,
  • 描述中涵盖了系统的 某一特定方面 ,而省略了此方面无关的 实体 。

9~16

软件系统中的复杂性有哪些种类

非功能需求包括哪些(三种)

NFRs(Non-functional requirements):非功能性需求:

  • Technical constraints 技术约束
  • Business constraints 业务约束
  • Quality attributes 质量属性
    是对整个系统性能等方面的 评估和验证
    (来源PPT 12)

软件架构过程(三个迭代步骤)

1)确定架构需求:架构上重要的需求(结构用例)—基本的质量和系统的非功能性需求
2)架构设计:迭代的设计步骤—风险识别是一个重要的输出设计
3)结构验证

  • 验证阶段—验证阶段的目的是增加信心的设计团队的架构是适合的目的;
  • 验证必须实现在项目时间和预算的约束,关键是要尽可能严格的和有效的;
  • 验证一个架构设计提出了严峻的挑战,因为这是一个设计不能执行或测试,包括新和COTS组件集成;
    (来源 doc ppt202)

软件质量属性主要包括哪些(五种)

  • Reliability 可靠性
    可靠性参数:平均故障间隔时间(MTBF),顾名思义,是硬件模块故障之间的平均时间。它是制造商在硬件模块发生故障之前估计的平均时间。
    FITS是表示MTBF的更直观的方式。FITS只是十亿小时(即1000,000,000小时)内模块的故障总数。
  • Availability 可用性
    衡量系统的可用性可以用公式 MTBF/(MTBF+MTTR),其中MTBF为系统出错的时间间隔也就是平均正常工作时间,而MTTR表示系统修复错误用的时间。当然上面的公式计算出的结果越大表示系统的可用性越好。
  • Portability 可移植性:跨平台
  • Scalability 可伸缩性:扩展的弹性
  • Performance (!) 性能:快

ppt1-8 116页

软件可用性取决于(三种时间)

Time to detect failure 故障 检测 时间

Time to correct failure 纠正 失败时间

Time to restart application 重新启动 应用程序时间
(PPT 146页)

伸缩性涉及那些方面(四种)

  • 伸缩性定义:(来源 百度百科) 可伸缩性/可扩展性(Scalable/scalability)
  • 可伸缩性(可扩展性)是一种对软件系统计算处理能力的设计指标,高可伸缩性代表一种弹性,在系统扩展成长过程中,软件能够保证旺盛的生命力,通过很少的改动甚至只是硬件设备的添置,就能实现整个系统处理能力的线性增长,实现高吞吐量和低延迟高性能。
  • 可伸缩性和纯粹性能调优有本质区别, 可伸缩性是高性能、低成本和可维护性等诸多因素的综合考量和平衡,可伸缩性讲究平滑线性的性能提升,更侧重于系统的水平伸缩,通过廉价的服务器实现分布式计算;而普通性能优化只是单台机器的性能指标优化。他们共同点都是根据应用系统特点在吞吐量和延迟之间进行一个侧重选择,当然水平伸缩分区后会带来CAP定理约束。
  • 纵向的可伸缩性——在同一个逻辑单元内增加资源来提高处理能力。这样的例子包括在现有服务器上增加CPU,或者在现有的RAID/SAN存储中增加硬盘来提高存储量。
  • 横向的可伸缩性——增加更多逻辑单元的资源,并令它们像是一个单元一样工作。大多数集群方案、分布式文件系统、负载平衡都是在帮助你提高横向的可伸缩性

1)Request load 请求负载
当同步请求负载增长时,100个tps应用程序的行为如何?如。
每秒100到1000个请求?
理想的解决方案,无需额外的硬件容量:
随着负载的增加,吞吐量保持不变(即100 tps),每个请求的响应时间只线性增加(即10秒)。

2)Connections 连接
如果与应用程序同时连接的数量增加,会发生什么情况呢
如果每个连接都消耗资源?
超过连接的最大数量?
ISP的例子:
每个用户连接生成一个新进程
每个服务器上的虚拟内存超过2000个用户
需要支持100k用户

3)Data size 数据大小
当应用程序处理的数据增大时,它的行为如何?
聊天应用程序平均消息大小翻倍?
数据库表大小从100万行增长到2000万行?
图像分析算法处理100MB而不是1MB的图像?
应用程序/算法能否扩展以处理增加的数据需求?

4)Deployments 部署
安装/部署应用程序的工作量如何随着安装基数的增长而增加?
安装新用户?
安装新的服务器?
解决方案通常围绕自动下载/安装
例如从互联网下载应用程式
ppt1-8 127页

吞吐率指标

PPT 120
Measure of the amount of work an application must perform in unit time
度量应用程序在单位时间内必须执行的工作量

  • Transactions per second 每秒事务数
  • Messages per minute 每分钟的消息

PPT 121
Throughput of a message queuing system :
消息队列系统的吞吐量

  • Messages per second (msp) 每秒的信息
  • Maximum sustainable throughput (MST) 最大可持续吞吐量

架构元素的通信包括哪些

(PPT ch1-ch8 slide210、212、218)

  • Synchronous communications 同步通信
  • Asynchronous communications 异步通信
  • Flexible communications 灵活通信

(PPT ch1-ch8 10)
Architecture Specifies Component Communication 体系结构指定组件通信
Communication involves: 架构元素的通信:

Data passing mechanisms 数据传递机制:

  • Function call 函数调用
  • Remote method invocation 远程方法调用
  • Asynchronous message 异步消息

Control flow 控制流

  • Flow of messages between components to achieve required functionality
    组件之间的消息流来实现需要的功能
  • Sequential 顺序
  • Concurrent/parallel 并发/并行
  • Synchronization 同步

17~24

各种架构风格的组件和连接器是什么

1)管道和过滤器架构风格PPT 40页
组件:称为过滤器,应用于对局部的输入流的转换,经常增长的计算,因此,在输入结束前输出就开始了。
连接器:称为管道,给流提供管道,把一个过滤器的输出传输到另一个输入。

2)面向对象风格 PPT49页
组件:对象
连接器:功能和过程调用(方法)

3)隐式调用风格
组件:模块(???)
连接器:广播系统
隐式调用系统中的连接器除了
事件通知 过程调用 之间的绑定外,
通常还包括 传统的过程调用

4)客户-服务器风格 PPT64页
组件:服务器:标准独立的组件提供特别的服务,如打印,数据管理等。客户端:组件调用服务器提供的服务。
连接器:网络,允许客户端访问远程服务器。

5)分层风格 PPT72页
组件:典型的过程的集合。
连接器:典型的在有限的可见性下的过程调用

6)仓库风格 PPT80页
组件
表示系统正确状态的中心数据结构。
A central data structure representing the correct state of the system.
操作中心数据结构的独立组件的集合。
A collection of independent components that operate on the central data structure.
连接器:典型地过程调用或是直接内存访问

7)解释程序风格 PPT87页
组件
包括执行引擎的一个状态机和三个内存:
include one state machine for the execution engine and three memories:
执行引擎的当前状态
current state of the execution engine
程序解释
program being interpreted
正在解释的程序的当前状态
current state of the program being interpreted
连接器
procedure calls 过程调用
direct memory accesses. 直接内存访问

8)过程控制风格 PPT94页
组件:过程定义:包括操作一些过程变量的机制,控制算法:决定如何去操作过程变量
连接器: 数据流关系 data flow relations

软件性能指标主要有哪几种(三种)

吞吐量、响应时间、最后期限 见第一题

响应时间的度量(两种)

Guaranteed time 最大响应时间
Average time 平均响应时间

PPT 122

安全性质量指标主要有哪几种(五种)

  • Authentication: Applications can verify the identity of their users and other applications with which they communicate.
    身份验证:应用程序可以验证他们的用户的身份和他们通信的其他应用程序。
  • Authorization: Authenticated users and applications have defined access rights to the resources of the system.
    授权:身份验证的用户和应用程序定义了系统资源的访问权限。
  • Encryption: The messages sent to/from the application are encrypted.
    加密:从应用程序发送到/从应用程序的消息是加密的。
  • Integrity: This ensures the contents of a message are not altered in transit.
    完整性:确保在传输过程中不会改变消息的内容。
  • Non-repudiation: The sender of a message has proof of delivery and the receiver is assured of the sender’s identity. This means neither can subsequently refute their participation in the message exchange.
    不可否认性:消息的发送方有交付证明,接收方可以确定发送方的身份。这意味着,双方随后都不能否认他们参与了信息交换。

PPT 142页

实现高可用性的策略(三种)

  • Eliminate single points of failure 消除单点故障
    是指一个系统的这样一个部件,如果它失效或停止运转,将会导致整个系统不能工作。我们当然不希望看到,在一个要求高度可用性的系统中存在这样的部分,但这种情况在网络,软件应用以及其它工业系统中都存在。
  • Replication and failover 复制和故障转移
    failover n. 失效备援(为系统备援能力的一种,当系统中其中一项设备失效而无法运作时,另一项设备即可自动接手原失效系统所执行的工作)
  • Automatic detection and restart 自动检测和重新启动

PPT 146

信息隐藏原理

PPT lecture 9 88页

  • 信息隐藏指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。
  • 信息隐藏(封装)主要是为了提高软件的可重用性和可维护性。信息隐藏造成了系统各个部分耦合性低。系统是由各个部分构成的,如果这些部分耦合性低的话,那么这个系统开发、维护等就较容易。
  • 假设A打算秘密传递一些信息给B,A需要从一个随机消息源中随机选取一个无关紧要的消息C,当这个消息公开传递时,不会引起人们的怀疑,称这个消息为载体对象(Cover Message)C;把秘密信息(Secret Message)M隐藏到载体对象C中,此时,载体对象就变成了伪装对象C1.载体对象C是正常的,不会引起人们的怀疑,伪装对象C1与载体对象C无论从感官(比如感受图像、视频的视觉和感受声音、音频的听觉)上,还是从计算机的分析上,都不可能把他们区分开来,而且对伪装对象C1的正常处理,不应破坏隐藏的秘密信息。这样就实现了信息的隐藏传输。秘密信息的嵌入过程可能需要密钥,也可能不需要密钥,为了区别于加密的密钥,信息隐藏的密钥称为伪装密钥k。

信息隐藏涉及两个算法:信息嵌入算法和信息提取算法,如下图:
信息隐藏的原理框图

什么是关注点,关注点的类型,关注点分离

SoC Separation of Concerns 是将软件分解为不同功能的过程,这些功能封装了可被其他类使用的独特行为和数据。 通常,关注点表示类的功能或行为。将程序分离成离散职责的行为显著地提高了代码重用、维护和可测试性。
在软件系统中,有两种主要的关注点类型:

  • 核心关注点 Core concern :它代表了系统基本的功能,并且是编写软件的主要原因。
  • 横切关注点 Cross-cutting concern :这是应用程序中依赖并影响其他关注点的一个方面。

关注点分离(Separation of concerns,SOC)

表示、业务和数据处理逻辑清楚地划分在不同的层中。

1)大体思路是,先将复杂问题做合理的分解,再分别仔细研究问题的不同侧面(关注点),最后综合各方面的结果,合成整体的解决方案。
2)是对只与“特定概念、目标”(关注点)相关联的软件组成部分进行“标识、封装和操纵”的能力,即标识、封装和操纵关注点的能力。是处理复杂性的一个原则。由于关注点混杂在一起会导致复杂性大大增加,所以能够把不同的关注点分离开来,分别处理就是处理复杂性的一个原则,一种方法。

关注点分离是面向方面的[程序设计]的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用(将针对特定领域问题代码抽象化成较少的程式码,例如将代码封装成function或是class),业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在在整个应用程序中的变动就可以很好的管理起来。
百度百科

什么是职责驱动的设计

Responsibility-Driven Design (RDD)

  • Detailed object design is usually done from the point of view of the metaphor of:
    详细的对象设计通常是从隐喻的角度进行的:
    1.Objects have responsibilities
    对象有责任
    2.Objects collaborate
    合作对象
  • Responsibilities are an abstraction.
    责任是抽象的。
    1.The responsibility for persistence.
    坚持的责任。
    Large-grained responsibility.
    大粒度的责任。
    2.The responsibility for the sales tax calculation.
    负责营业税的计算。
    More fine-grained responsibility.
    更细粒度的责任。
    ppt
  • 职责驱动设计即如何给相互协作的对象分配职责,主要关注的是职责、角色以及协作。
  • 职业驱动设计就是职责必须匹配。
    什么是职责呢?简单地说,一个类或构件的职责包括两个方面:
    一个是知道的事,对于一个类来说就是他的属性;
    一个是能做的事,对于一个类来说就是他的方法。
    百度百科

25~32

GRASP模式的具体内容,各种模式的定义,解决的什么问题

1)创造者 Creator
分配给类B职责来创造类A的一个实例如果:
(1) B聚合A的对象
(2) B包含A的对象
(3) B记录A的对象的实例
(4) B紧密地使用A的对象
(5) B被创建时有初始化的数据传递给

解决方案:将创建一个类A的实例的职责指派给类B的实例,
如果下列条件满足的话:
a) B聚合了A对象
b) B包含了A对象
c) B纪录了A对象的实例
d) B要经常使用A对象
e) 当A的实例被创建时,B具有要传递给A的初始化数据(也就是说B是创建A的实例这项任务的信息专家)
f) B是A对象的创建者
如果以上条件中不止一条成立的话,那么最好让B聚集或包含A

通俗点就是:我要用你所以我来创建你,请不要让别人创建你
这个模式是支持低耦合度原则的一个体现

2)信息专家 Information Expert
在设计对象(类)时,如果某个类能够在某方面具有完整信息,足以实现某责任,就将这个责任分配给这个类,
解决方案:将职责分配给具有履行职责所需要的信息的类
通俗点就是:该干嘛干嘛去,别管别人的闲事或者我的职责就是搞这个,别的事不管。
举个简单的例子,如果有一个类是专门处理字符串相关的类,那么这个类只能有字符串处理相关的方法,而不要将日期处理的方法加进来。也就是提高软件高内聚一种原则。

3)控制器 Controller
控制器是在用户接口层上的第一个对象,负责接收和处理系统的操作信息。
解决方案:将处理系统事件消息的职责分派给代表下列事物的类:
a) 代表整个“系统”的类(虚包控制者)
b) 代表整个企业或组织的类(虚包控制者)
c) 代表真实世界中参与职责(角色控制者)的主动对象类(例,一个人的角色)
d) 代表一个用况中所有事件的人工处理者类,通常用“<用例名>处理者”的方式命名(用例控制者)
这是一个控制者角色职责分配的原则,就是哪些控制应该分派给哪个角色。

4)低耦合 Low Coupling
测量存在于模块之间的依赖程度
解决方案:在分配一个职责时要使保持低耦合度。
耦合度(coupling)是一个类与其它类关联、知道其他类的信息或者依赖其他类的强弱程度的度量。一个具有低(弱)耦合度的类不依赖于太多的其他类。

5)高内聚 High Cohesion
测量一个共享的模块内元素的相关性 ;一个单独模块执行任务的程度是功能相关的
解决方案:分配一个职责的时候要保持类的高聚合度
聚合度或内聚度(cohesion)是一个类中的各个职责之间相关程度和集中程度的度量。一个具有高度相关职责的类并且这个类所能完成的工作量不是特别巨大,那么他就是具有高聚合度。

6)多态 Polymorphism
当相关的供选方案或行为随着类型的变化而变化时,给行为分配职责—使用多态操作—来适合行为变化的类型。
也就是说尽量对抽象层编程,用多态的方法来判断具体应该使用那个类,而不是用if instanceof 来判断该类是什么接来执行什么。

7)纯虚构 Pure Fabrication
分配一系列高度聚合的职责给虚假的类或是不表现某事完成的领域问题概念的有用的类,它支持高内聚、低耦合、可重用。
一个纯虚构意味着虚构某些事物,而不是到了迫不得已我们才这样做。
例,我们的Sale类的数据要存入数据库,但是他必须和数据库接口相连接,如果将接口连接放入Sale类中势必增加该类的耦合度,所以我们可以虚构一个类来处理与数据库接口连接的问题。这个类就是我们虚构出来的一个事物。

8)间接 Indirection
问题:如何分配职责避免直接耦合?如何减弱对象的耦合?
解决方案:分配职责给中间的调解对象来调解两个组件之间的关系。
内容:将职责分配给一个中间对象以便在其他构件或服务之间仲裁,这样这些构件或服务没有被直接耦合。这个中间对象(intermediary)在其他构件或服务间创建一个中介者(Indirection)。这个中间对象也就事7)中的纯虚构。

9)防止编译/变化预防 Protected Variations
问题:如何设计对象,子系统和系统,使其内部的变化和不稳定不会对其他元素产生不良影响?
解决方案:识别设计变化或不稳定之处,分配职责用以在这些变化之外创建稳定接口
内容:分配职责给一个客户端的直接对象以使它与一个间接对象进行协作,这样客户端无需知道这个间接对象。
这个模式-也被叫做(Demeter)准则。
通俗点就是:只与你直接的朋友们通信,不要跟“陌生人”说话,每个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位

GRASP的主要特征:

  • 对象职责分配的基本原则。
  • 主要应用在分析和建模上。

GRASP的核心思想的理解:

  • 自己干自己的事(职责的分配)
  • 自己干自己的能干的事(职责的分配)
  • 自己只干自己的事(职责的内聚)

来源 doc

OO设计的五个基本原则及课件中讲述的其它软件原理(主要在Java review PPT中)

五个基本原则:(S.O.L.I.D):
1)单一职责原则 (SPR 单一功能原则)
这个原则和关注点分离紧密联系。它陈述了每个对象应该只有一个理由去改变,单一聚焦在职责上。通过依附这个原则,你避免了庞大的类的设计问题,那就像瑞士的军刀。有了精确的对象,你再次增加了系统的可读性和可维护性。

2)开闭原则 (OCP 开闭原则)
这个原则陈述了类应该对扩展开放,对修改关闭,那样你就能够添加新的特征,扩展一个类而不用改变它内部的行为。这个原则旨在避免破坏存在的类及依赖它的其他类,这使得你的整个应用程序中产生故障和错误的涟漪。

3)Liskov替换原则 (LSP 里式替换原则)
Liskov替换原则要求你应该能够使用任何衍生出的类代替父类,不用修改就有同样的行为。这个原则与开闭原则一致,它保证了一个衍生出的类不影响父类的行为,或者说,衍生出的类必须能够被它们的基类替代。

4)接口分离原则 (ISP 接口隔离原则)
这个原则是将一个抽象方法分裂成几组职责,给这些组分配接口来防止客户端实现一个很大的接口,这个接口容纳了很多它们不使用的方法。目的是为了让类使用相同的接口只需要实现一些具体的方法,而不是有很多方法的庞大的接口。不应强迫客户程序实现一个它用不上的接口。

5)依赖反转原则 (DIP依赖反转原则)
把你的类从具体的实现中隔离开,使它们依赖于抽象类或接口。它促进了对接口而不是实现的译码,这通过保证对实现的低耦合来增加系统的灵活性。
高层模块不应该依赖于底层模块。二者都应该依赖于抽象
抽象不应该依赖于细节,细节应该依赖于抽象

更多解释:
https://blog.csdn.net/zn_echonn/article/details/80198053

【其它基本原理】
A.保持代码简单而不过于简单,避免不必要的复杂性;
B.把公共事物抽象出来,放在固定的位置;
C.给类分配正确的职责,告诉对象做什么,而不是询问对象的状态;
D.把自认为需要却不一定需要的特性延迟;
E.把特性分离封装成类,增强重用、维护和稳定。(关注点分离)
F.将类及其成员的访问性降到最小;
G.使用访问器和修改器,而不是公共成员;
H.组合优于继承;
I.面向接口编程,而不是实现。

  • 面向抽象原则
    设计一个类时,不让该类面向具体的类,而是面向抽象类或接口
  • 高内聚-低耦合原则
    如果类中的方法是一组相关的行为,则称该类是高内聚的,反之称为低内聚的。 所谓低耦合就是尽量不要让一个类含有太多的其它类的实例的引用,以避免修改系统的其中一部分会影响到其它部分。

组合,继承,针对接口编程,黑盒,白盒重用

1)组合:
指在新类里面创建原有类的对象,重复利用已有类的功能。

优点:
包含对象由包含类通过其接口访问
“黑盒”重用,因为包含对象的内部细节不可见

  • 良好的封装
  • 更少的实现依赖性
  • 每个类只关注一个任务
  • 可以在运行时通过获取对相同类型的其他对象的引用的对象来动态地定义组合
    缺点:
    结果系统往往有更多的对象
    接口必须仔细定义,以便使用许多不同的对象作为组合块

2)继承:

新功能的重用方法获得通过扩展现有对象的实现 ???
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
泛化类(超类)明确了共同的属性和方法
专业类(子类)扩展了实现额外的属性和方法

优点:
新的实现很容易,因为它的大部分是继承的
容易修改或扩展的实现被重用
缺点:
打破封装,因为它暴露一个子类到其超类的实现细节
“白盒”重用,因为超类的内部细节对子类通常是可见的
如果超类的实现更改,则可能必须更改子类
从超类继承的实现不能在运行时更改

3)针对接口编程又称为面向接口编程,

针对接口编程就是要先设计以系列的接口,把设计和实现分开,使用时只需要引用接口即可,也由于系统各部分的解耦合。针对接口编程是为了提高程序的可维护性、可伸缩性和可复用性。如果你在一个类中直接使用另外的一个,这样就把两个类紧密联系在一起了,以后如果想做出改变就很难了。如果针对接口编程,当业务变化时我们只需要用一个新的类实现接口即可

优点:
客户端不知道他们正在使用的对象的特定类
一个对象可以很容易地被另一个替换
对象连接不需要硬连线到特定类的对象,从而增加了灵活性
松耦合
增加重复使用的可能性
改进合成的机会,因为包含的对象可以是实现特定接口的任何类
缺点:
适度增加设计复杂性

4)白盒复用:
源代码可见,可修改和扩展
– 复制已有代码当正在开发的系统,进行修改
– 可定制化程度高
– 对其修改增加了软件的复杂度,且需要对其内部充分的了解

白盒重用”White-box” reuse(PPT Review of Java Slide 45)
“White-box” reuse, since internal details of super classes are often visible to subclasses
“白盒”重用,因为超类的内部细节对子类通常是可见的

5)黑盒复用:
源代码不可见,不能修改
– 只能通过API接口来使用,无法修改代码
– 简单,清晰
– 适应性差些

黑盒重用”Black-box” reuse(PPT Review of Java Slide 43)
“Black-box” reuse, since internal details of contained objects are not visible
因为包含对象的内部细节不可见

  • 补充:
    组合(has-a)关系可以显式地获得被包含类(继承中称为父类)的对象,而继承(is-a)则是隐式地获得父类的对象,被包含类和父类对应,而组合外部类和子类对应。

组合关系是 局部类和整体类的关系
继承关系 父类和子类的关系
(来源doc,网络)

什么是抽象,封装

封装 Encapsulation
阻止你知道,封装帮助控制偶然复杂性,尽可能地隐藏实现细节。封装意味着我们永远不希望客户端开发人员知道一个调用的操作是如何实现的。

抽象 Abstraction

  • 忽视一个问题中与当前目的无关的那些方面的原则,以便只集中注意与当前目的有关的那些方面。
  • 允许忽略

MVC模式

(来源DOC)

  • MVC是 模型-视图-控制器 的缩写
    它代表了一种软件设计模式,1978年开发在施乐帕克研究中心(!)
    它解释了一种分离视觉、交互和数据组件的方法。
    非常受欢迎,广泛用于Java和其他语言

(百度百科)

  • Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。
    通常模型对象负责在数据库中存取数据。
  • View(视图)是应用程序中处理数据显示的部分。
    通常视图是依据模型数据创建的。
  • Controller(控制器)是应用程序中处理用户交互的部分。
    通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

模型 :维护应用程序的状态和数据的XML文档

  • “模型”包含的数据
  • 有一些方法来访问并可能更新它的内容。
  • 通常,它实现了一个允许模型交互的接口。
  • 实现了一个允许退出和取代的接口,并不伴随编程改变

视图 :XML文档的呈现

  • 视图提供模型的可视化表示。
  • 在任何时候都可以有多个视图表示模型。
  • 例如,一个公司财务状况随着时间的推移可以用一个表和图表示。
  • 只有两种不同的视图表示相同的数据。
  • 当模型更新时,所有视图被通知然后有机会更新

控制器 :用户界面呈现给用户操作的应用程序

  • 用户与控制器进行交互。
  • 它解释鼠标移动,点击按键等
  • 活动与模型沟通,如:删除行,插入行等
  • 它的模型的交互间接导致视图的更新

企业应用架构有那三层,各层主要做什么。在各层有那些主要的模式,各层的各种模式的定义和结构内容(展现层,领域层,数据源层)

(PPT ch9 slide 110)
1)表现层:提供服务,显示信息。页面控制器,模板视图,前端控制器,转换视图。
2)领域层:领域逻辑,领域中真正的核心。也称为业务逻辑,它是应用程序必须做的所有领域相关工作:包括根据输入数据和已有数据进行计算,对从表现层输入的数据进行验证以及根据从表现层接受的命令来确定应该调试哪些数据源逻辑。事物脚本,领域模型,表模块,活动记录。
3)数据源层:与数据库、系统消息系统、事务管理器及其他软件包进行通信。最主要的数据源逻辑就是数据库,主要责任是存储持久数据。行数据网关,表数据网关,数据映射程序,表模块,活动记录。

Larman的敏捷UP设计方法的具体步骤(Larman’s Design Process)

s Design Process

4+1视图

“4+1”视图模型即从5个不同的视角(逻辑视图,进程视图,物理视图,开发视图
和场景视图)来描述软件体系结构。
每个视图之关心系统的一个侧面,5个视图结合在一起才能反映系统的软件体系结构的全部内容。

逻辑视图(Logical View):
过程视图:描述架构元素之间的并发和通信
物理视图:描绘主要的过程和组件是如何映像到硬件上的
开发视图:俘获软件组件内部的结构,如配置管理工具

架构用例:俘获架构的需求;和不止一种视图相关

百度百科
逻辑视图(Logical View)设计的对象模型(使用[面向对象]的设计方法时)。
过程视图(Process View)捕捉设计的并发和同步特征。
物理视图(Physical View)描述了软件到硬件的映射,反映了分布式特性。
开发视图(Development View)描述了在[开发环境]中软件的静态组织结构。

架构的描述,即所做的各种决定,可以围绕着这四个视图来组织,然后由一些用例 (use cases)或场景(scenarios)来说明,从而形成了第五个视图。

33~35

应用的集成策略

  • Data – expose application data for access by other components
    公开应用程序数据供其他组件访问
  • API – offers services to read/write application data through an abstracted interface
    即数据——公开应用程序数据访问的其他组件,提供服务来读/写应用程序数据通过一个抽象接口

API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

来源DOC

补充内容:
1.一些指标

  • Performance:Application performance must provide sub-four second response times for 90% of requests.
    性能:应用程序性能人工跑道跑四秒的响应时间必须提供90%的请求。
  • Security: All communications must be authenticated and encrypted using certificates.
    安全性:所有通信都必须使用证书进行身份验证和加密。
  • Resource Management:The server component must run on a low end office-based server with 512MB memory.
    资源管理:服务器组件必须运行在一个低端办公室服务器512 mb内存。
  • Usability:The user interface component must run in an Internet browser to support remote users.
    可用性:用户界面组件必须运行在一个网络浏览器支持远程用户。
  • Availability: The system must run 24x7x365, with overall availability of 0.99.
    有效性:系统必须运行24x7x365,总体可用性为0.99。
  • Reliability:No message loss is allowed, and all message delivery outcomes must be known with 30 seconds
    可靠性:没有信息损失是允许的,和所有的消息传递的结果必须是已知的30秒
  • Scalability:The application must be able to handle a peak load of 500 concurrent users during the enrollment period.
    可伸缩性:应用程序必须能够处理500个并发用户的峰值负载在招生期间。
  • Modifiability: The architecture must support a phased migration from the current Forth Generation Language (4GL) version to a .NET systems technology solution.
    可修改性:体系结构必须支持从当前的第四代语言(4GL)版本到. net系统技术解决方案的阶段性迁移。

掌握:

命令模式,状态模式,装饰模式,观察者模式,策略模式,单例模式,工厂方法模式,组合模式,适配器模式,外观模式,责任链模式的UML图和java代码

命令模式(Command Pattern):

UML:
@startuml
interface Command {
    {abstract} +execute()
}

class ConcreteCommand implements Command {
    +execute()
}

class Invoker {
    -command: Command
    +setCommand(command: Command)
    +executeCommand()
}

class Receiver {
    +action()
}

ConcreteCommand --> Receiver
Invoker --> Command
ConcreteCommand --> Invoker
@enduml
java代码:
// Implement Command interface
interface Command {
    void execute();
}

// Concrete Command
class ConcreteCommand implements Command {
    private Receiver receiver;
    
    ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }
    
    public void execute() {
        receiver.action();
    }
}

// Invoker
class Invoker {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void executeCommand() {
        command.execute();
    }
}

// Receiver
class Receiver {
    public void action() {
        // Perform action
    }
}

状态模式(State Pattern):

UML:
@startuml
interface State {
    {abstract} +handle()
}

class ConcreteStateA implements State {
    +handle()
}

class ConcreteStateB implements State {
    +handle()
}

class Context {
    -state: State
    +request()
}

ConcreteStateA --> State
ConcreteStateB --> State
ConcreteStateA --> Context
ConcreteStateB --> Context
@enduml
java代码:
// State interface
interface State {
    void handle();
}

// Concrete States
class ConcreteStateA implements State {
    public void handle() {
        // Handle state A
    }
}

class ConcreteStateB implements State {
    public void handle() {
        // Handle state B
    }
}

// Context
class Context {
    private State state;
    
    public void request() {
        state.handle();
    }
}

装饰模式(Decorator Pattern):

UML:
@startuml
interface Component {
    {abstract} +operation()
}

class ConcreteComponent implements Component {
    +operation()
}

class Decorator implements Component {
    -component: Component
    {abstract} +operation()
}

class ConcreteDecoratorA implements Decorator {
    +operation()
}

class ConcreteDecoratorB implements Decorator {
    +operation()
}

ConcreteDecoratorA --> Decorator
ConcreteDecoratorB --> Decorator
Decorator --> Component
ConcreteDecoratorA --> ConcreteComponent
ConcreteDecoratorB --> ConcreteComponent
@enduml
java代码:
// Component interface
interface Component {
    void operation();
}

// Concrete Component
class ConcreteComponent implements Component {
    public void operation() {
        // Perform operation
    }
}

// Decorator interface
interface Decorator extends Component {
    // Additional methods if needed
}

// Concrete Decorators
class ConcreteDecoratorA implements Decorator {
    private Component component;
    
    ConcreteDecoratorA(Component component) {
        this.component = component;
    }
    
    public void operation() {
        // Additional operation
        component.operation();
    }
}

class ConcreteDecoratorB implements Decorator {
    private Component component;
    
    ConcreteDecoratorB(Component component) {
        this.component = component;
    }
    
    public void operation() {
        // Additional operation
        component.operation();
    }
}

观察者模式(Observer Pattern):

UML:
@startuml
interface Observer {
    {abstract} +update()
}

class ConcreteObserverA implements Observer {
    +update()
}

class ConcreteObserverB implements Observer {
    +update()
}

class Subject {
    -observers: List<Observer>
    {abstract} +attach(observer: Observer)
    {abstract} +detach(observer: Observer)
    {abstract} +notifyObservers()
}

class ConcreteSubject implements Subject {
    +attach(observer: Observer)
    +detach(observer: Observer)
    +notifyObservers()
}

ConcreteObserverA --> Observer
ConcreteObserverB --> Observer
ConcreteObserverA --> ConcreteSubject
ConcreteObserverB --> ConcreteSubject
ConcreteSubject --> Observer
@enduml
java代码:
import java.util.ArrayList;
import java.util.List;

// Observer interface
interface Observer {
    void update();
}

// Concrete Observers
class ConcreteObserverA implements Observer {
    public void update() {
        // Update logic for Observer A
    }
}

class ConcreteObserverB implements Observer {
    public void update() {
        // Update logic for Observer B
    }
}

// Subject interface
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// Concrete Subject
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

策略模式(Strategy Pattern):

UML:
@startuml
interface Strategy {
    {abstract} +algorithm()
}

class ConcreteStrategyA implements Strategy {
    +algorithm()
}

class ConcreteStrategyB implements Strategy {
    +algorithm()
}

class Context {
    -strategy: Strategy
    {abstract} +setStrategy(strategy: Strategy)
    +execute()
}

ConcreteStrategyA --> Strategy
ConcreteStrategyB --> Strategy
ConcreteStrategyA --> Context
ConcreteStrategyB --> Context
@enduml
java代码:
// Strategy interface
interface Strategy {
    void algorithm();
}

// Concrete Strategies
class ConcreteStrategyA implements Strategy {
    public void algorithm() {
        // Implement algorithm A
    }
}

class ConcreteStrategyB implements Strategy {
    public void algorithm() {
        // Implement algorithm B
    }
}

// Context
class Context {
    private Strategy strategy;
    
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public void execute() {
        strategy.algorithm();
    }
}

单例模式(Singleton Pattern):

UML:
@startuml
class Singleton {
    -instance: Singleton
    {static} +getInstance(): Singleton
    -Singleton()
}
@enduml
java代码:
// Singleton class
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {
        // Private constructor to prevent instantiation
    }
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

工厂方法模式(Factory Method Pattern):

UML:
@startuml
interface Product {
    {abstract} +create()
}

class ConcreteProductA implements Product {
    +create()
}

class ConcreteProductB implements Product {
    +create()
}

interface Creator {
    {abstract} +factoryMethod(): Product
}

class ConcreteCreatorA implements Creator {
    +factoryMethod(): Product
}

class ConcreteCreatorB implements Creator {
    +factoryMethod(): Product
}

ConcreteProductA --> Product
ConcreteProductB --> Product
ConcreteProductA --> ConcreteCreatorA
ConcreteProductB --> ConcreteCreatorB
ConcreteCreatorA --> Creator
ConcreteCreatorB --> Creator
@enduml
java代码:
// Product interface
interface Product {
    void create();
}

// Concrete Products
class ConcreteProductA implements Product {
    public void create() {
        // Create product A
    }
}

class ConcreteProductB implements Product {
    public void create() {
        // Create product B
    }
}

// Creator interface
interface Creator {
    Product factoryMethod();
}

// Concrete Creators
class ConcreteCreatorA implements Creator {
    public Product factoryMethod() {
        return new ConcreteProductA();
    }
}

class ConcreteCreatorB implements Creator {
    public Product factoryMethod() {
        return new ConcreteProductB();
    }
}

组合模式(Composite Pattern):

UML:
@startuml
interface Component {
    {abstract} +operation()
}

class Leaf implements Component {
    +operation()
}

class Composite implements Component {
    -children: List<Component>
    {abstract} +operation()
    +add(component: Component)
    +remove(component: Component)
}

Leaf --> Component
Composite --> Component
Leaf --> Composite
@enduml
java代码:
import java.util.ArrayList;
import java.util.List;

// Component interface
interface Component {
    void operation();
}

// Leaf
class Leaf implements Component {
    public void operation() {
        // Leaf operation
    }
}

// Composite
class Composite implements Component {
    private List<Component> children = new ArrayList<>();
    
    public void operation() {
        // Composite operation
        for (Component component : children) {
            component.operation();
        }
    }
    
    public void add(Component component) {
        children.add(component);
    }
    
    public void remove(Component component) {
        children.remove(component);
    }
}

适配器模式(Adapter Pattern):

UML:
@startuml
interface Target {
    {abstract} +request()
}

class Adaptee {
    +specificRequest()
}

class Adapter implements Target {
    -adaptee: Adaptee
    +request()
}

Adaptee --> Target
Adapter --> Target
Adapter --> Adaptee
@enduml
java代码:
// Target interface
interface Target {
    void request();
}

// Adaptee
class Adaptee {
    public void specificRequest() {
        // Adaptee specific request
    }
}

// Adapter
class Adapter implements Target {
    private Adaptee adaptee;
    
    Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    
    public void request() {
        adaptee.specificRequest();
    }
}

外观模式(Facade Pattern):

UML:
@startuml
class SubsystemA {
    +operationA()
}

class SubsystemB {
    +operationB()
}

class SubsystemC {
    +operationC()
}

class Facade {
    -subsystemA: SubsystemA
    -subsystemB: SubsystemB
    -subsystemC: SubsystemC
    +operation()
}

SubsystemA --> Facade
SubsystemB --> Facade
SubsystemC --> Facade
@enduml
java代码:
// SubsystemA
class SubsystemA {
    public void operationA() {
        // SubsystemA operation
    }
}

// SubsystemB
class SubsystemB {
    public void operationB() {
        // SubsystemB operation
    }
}

// SubsystemC
class SubsystemC {
    public void operationC() {
        // SubsystemC operation
    }
}

// Facade
class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;
    private SubsystemC subsystemC;
    
    Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
        subsystemC = new Subsystem

责任链模式 (Chain of Responsibility Pattern)

UML:
@startuml
interface Handler {
    {abstract} +handleRequest(request: Request): void
}

class ConcreteHandler1 implements Handler {
    - successor: Handler
    +handleRequest(request: Request): void
}

class ConcreteHandler2 implements Handler {
    - successor: Handler
    +handleRequest(request: Request): void
}

class Request {
    +getRequestType(): String
}
Handler <|.. ConcreteHandler1
Handler <|.. ConcreteHandler2
@enduml
java代码:
// Handler interface
public interface Handler {
    void handleRequest(Request request);
}

// ConcreteHandler1 class
public class ConcreteHandler1 implements Handler {
    private Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public void handleRequest(Request request) {
        if (request.getRequestType().equals("Type1")) {
            // Handle the request
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// ConcreteHandler2 class
public class ConcreteHandler2 implements Handler {
    private Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public void handleRequest(Request request) {
        if (request.getRequestType().equals("Type2")) {
            // Handle the request
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// Request class
public class Request {
    private String requestType;

    public String getRequestType() {
        return requestType;
    }

    // Other methods...
}

凡是课件里有关架构的具体例子(一般都有UML图或有代码)都需要仔细体会,重点搞清楚实验指导书里的各个步骤过程怎么做的。


文章作者: KeyenZhou
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 KeyenZhou !
  目录