8. 可修改性

第8章 可修改性

它不是生存下来的最强壮的物种,也不是最聪明的物种,而是对变化最敏感的物种。

—Charles Darwin

变化发生了。

一项又一项的研究表明,典型软件系统的大部分成本发生在最初发布之后。如果变化是宇宙中唯一的事情,那么软件变更不仅是常态的,而且无处不在。在添加新功能时发生变更,甚至在停用旧功能时发生变更。为了修复缺陷、加强安全性或提高性能而变更。变更是为了增强用户体验。为包含新技术、新平台、新协议、新标准而变更。变更使系统协同工作,即使它们从未被设计为这样做。

可修改性是关于变化的,我们对它的兴趣是降低进行更改的成本和风险。要规划可修改性,架构师必须考虑四个问题:

  • 可以变更什么? 系统的任何方面都可能发生变更:系统计算的功能,平台(硬件,操作系统,中间件),系统运行的环境(必须与之互操作的系统,用于与世界其他地方通信的协议),系统表现出的质量(性能, 它的可靠性,甚至它未来的修改),以及它的容量(支持的用户数量,同时操作的数量)。

  • *变更的可能性有多大?*一个人不可能为所有潜在的变更规划一个系统——系统永远不会完成,或者如果这样做了,它将过于昂贵,并且可能会在其他维度上遇到质量属性问题。尽管任何部分都 可能 发生变更,但架构师必须做出艰难的决定,确定哪些变更是可能的,因此哪些变更将得到支持,哪些不会。

  • 何时进行变更以及谁进行变更? 过去最常见的是对源代码进行变更。也就是说,开发人员必须进行变更,该变更经过测试,然后在新版本中部署。然而,现在,何时进行变更的问题与谁进行变更的问题交织在一起。变更屏幕保护程序的最终用户显然是对系统的一个方面进行变更。同样清楚的是,它与变更系统以使用不同的数据库管理系统不属于同一类别。可以在实现期间(通过修改源代码)、编译期间(使用编译时开关)、生成期间(通过选择库)、配置设置期间(通过一系列技术,包括参数设置)或执行期间(通过参数设置、插件、分配给硬件等)进行更改。开发人员、最终用户或系统管理员也可以进行变更。自学习和自适应的系统为何时进行变更以及“谁”进行变更的问题提供了完全不同的答案 - 系统本身是变更的推动者。

  • 变更的成本是多少? 使系统更具可修改性涉及两种类型的成本:

    • 引入机制以使系统更易于修改的成本

    • 使用机制进行修改的成本

例如,进行变更的最简单机制是等待变更请求进来,然后更改源代码以适应请求。在这种情况下,引入该机制的成本为零(因为没有特殊机制);执行它的成本是更改源代码和重新验证系统的成本。

另外一个极端是应用程序生成器,例如用户界面构建器。构建器输入UI 设计(通过直接操作技术生成)的描述,然后可以生成源代码。引入该机制的成本是获取 UI 构建器的成本,这可能很大。使用该机制的成本是产生输入以馈送构建器的成本(此成本可能很大或可以忽略不计),运行构建器的成本(接近于零),最后是对结果执行任何测试的成本(通常远低于手动编码)。

更进一步的是软件系统,它们发现其环境,学习并修改自己以适应任何变化。对于这些系统,进行修改的成本为零,但这种能力是在实施和测试它的学习机制的同时购买的,这可能非常昂贵。

对于 N 个相似的修改,对于更改机制的一个简化的判断理由是

N * 在没有机制的情况下进行更改的成本 ≤
创建机制的成本 + (N * 使用该机制进行更改的成本)

在这里,N 是将使用可修改性机制的预期修改数量,但它也是一个预测。如果变更少于预期,则可能不需要昂贵的修改机制。此外,创建可修改性机制的成本可以应用于其他地方(机会成本)——添加新功能、提高性能,甚至非软件投资,如招聘或培训。此外,该等式不考虑时间。从长远来看,构建复杂的变更处理机制可能会更便宜,但你可能无法等待它的完成。但是,如果你的代码经常修改,不引入一些架构机制并简单地将变更堆积在变更之上通常会导致大量的技术债务。我们在 第23章 中讨论了架构债务的主题。

变更在软件系统的生命周期中是如此普遍,以至于为特定的可修改性赋予了特殊名称。这里突出显示了一些常见的:

  • 可扩展性 是关于容纳更多的东西。在性能方面,可扩展性意味着添加更多资源。两种性能可伸缩性是水平可伸缩性和垂直可伸缩性。水平可伸缩性(横向扩展)是指向逻辑单元添加更多资源,例如将另一台服务器添加到服务器群集。垂直可伸缩性(纵向扩展)是指向物理单元添加更多资源,例如向单台计算机添加更多内存。这两种类型的扩展都会出现的问题是如何有效地利用额外的资源。“有效”意味着额外的资源可以显著改善某些系统质量,不需要过度努力来添加,也不会过度中断操作。在基于云的环境中,水平可伸缩性称为弹性。弹性是一种属性,它使客户能够在资源池中添加或删除虚拟机(有关此类环境的进一步讨论,请参阅 第17章)。

  • 可变性 是指系统及其支持工件(如代码、需求、测试计划和文档)支持以预先计划的方式生成一组彼此不同的变体的能力。可变性是产品线中一个特别重要的质量属性,产品系列是一系列相似但特性和功能不同的系统。如果与这些系统相关的工程资产可以在家族成员之间共享,那么产品线的总体成本就会直线下降。这是通过引入允许选择工件和/或适应产品线范围内不同产品背景中的用法的机制来实现的。软件产品线可变性的目标是在一段时间内轻松构建和维护该系列中的产品。

  • 可移植性 是指将构建为在一个平台上运行的软件更改为在不同平台上运行的难易程度。可移植性是通过最小化软件中的平台依赖关系、将依赖关系隔离到标识良好的位置以及编写软件以在封装所有平台依赖关系的“虚拟机”(例如 Java 虚拟机)上运行来实现的。描述可移植性的情形涉及将软件移动到新平台,方法是花费不超过一定程度的努力或计算软件中必须更改的位置数量。处理可移植性的架构方法与 第5章 中讨论的主题 可部署性 的架构方法交织在一起。

  • 位置独立性 是指两个分布式软件交互,并且在运行时之前不知道其中一个或两个部分的位置的情况。或者,这些片段的位置可能会在运行时更改。在分布式系统中,服务通常部署到任意位置,这些服务的客户端必须动态发现其位置。此外,分布式系统中的服务在部署到某个位置后,通常必须使其位置可被发现。设计系统时具有位置独立性意味着位置易于修改,对系统其余部分的影响最小。

8.1 可修改性通用情形

根据这些考虑,我们可以构建可修改性的通用情形。表8.1 总结了此情形。

表8.1 可修改性的通用情形情形

情形部分描述可能的值
来源导致进行变更的因素。大多数是人类参与者,但系统可能是自学习或自我修改的系统,在这种情况下,来源是系统本身。最终用户、开发人员、系统管理员、产品线所有者、系统本身
触发事件系统需要适应的变更。(对于此分类,我们将修复缺陷视为对可能无法正常工作的变更。添加/删除/修改功能或更改质量属性、能力、平台或技术的指令;将新产品添加到产品线的指令;将服务位置更改为另一个位置的指令
工件修改的项目。特定组件或模块、系统平台、用户界面、环境或与之互操作的其他系统。代码、数据、接口、组件、资源、测试用例、配置、文档
环境进行变更的时间或阶段。运行时、编译时、构建时、启动时、设计时
响应进行变更并将其合并到系统中。以下一项或多项:
  • 执行修改
  • 测试修改
  • 部署修改
  • 自我修改
响应度量为进行变更而花费的资源。成本方面:
  • 受影响工件的数量、大小、复杂性
  • 工作量
  • 经历的时间
  • 金钱(直接支出或机会成本)
  • 此修改对其他功能或质量属性的影响程度
  • 新引入的缺陷
  • 系统适配需要多长时间

图8.1 说明了一个具体的可修改性情形: 开发人员希望变更用户界面。此变更将在设计时对代码进行,执行和测试变更所需的时间不到三个小时,并且不会产生副作用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图8.1 具体可修改性情形示例

8.2 可修改性的策略

控制可修改性的策略的目标是控制进行变更的复杂性,以及进行变更的时间和成本。图8.2 显示了这种关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图8.2 可修改性策略的目标

为了理解可修改性,我们从软件设计中一些最早和最基本的复杂性度量开始 - 耦合和内聚 - 这些度量在1960年代首次被描述。

通常,影响一个模块的变更比影响多个模块的变更更容易且成本更低。但是,如果两个模块的职责以某种方式重叠,那么单个变更很可能会同时影响它们。我们可以通过测量对一个模块的修改传播到另一个模块的概率来量化这种重叠。这种关系称为 耦合,高度耦合是可修改性的敌人。减少两个模块之间的耦合将降低影响任何一个模块的任何修改的预期成本。减少耦合的策略是在两个高度耦合的模块之间放置各种中介的策略。

内聚力 用于衡量模块职责的相关性。非正式地,它衡量模块的“目的统一性”。目的的统一可以通过影响模块的更改方案来衡量。模块的内聚力是影响职责的变更方案也会影响其他(不同)职责的概率。内聚力越高,给定变更影响多个模块的可能性就越低。高内聚力有利于可改性;低内聚力则对它不利。如果模块 A 的内聚力较低,则可以通过移除不受预期变更影响的职责来改善内聚力。

影响变更成本和复杂性的第三个特征是模块的 大小。在所有其他条件相同的情况下,较大的模块更难变更,成本更高,并且更容易出现错误。

最后,我们需要关注软件开发生命周期中发生变更的点。如果我们忽略为修改而准备的架构的成本,我们宁愿变更尽可能晚。只有在架构为适应变更做好适当准备的情况下,才能在生命周期的后期成功进行更改(即快速且低成本)。因此,可修改性模型中的第四个也是最后一个参数是 修改的绑定时间。平均而言,在生命周期后期适当地适应修改的架构的成本将低于强制提前进行相同修改的架构。系统的准备情况意味着,对于生命周期后期发生的修改,一些成本将为零或非常低。

现在我们可以理解策略及其后果会影响以下一个或多个参数:减小尺寸、增加内聚力、减少耦合和延迟绑定时间。这些策略如图8.3所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图8.3 可修改性策略

增加内聚

有几种策略涉及在模块之间重新分配职责。执行此步骤是为了降低单个变更影响多个模块的可能性。

  • 拆分模块。如果正在修改的模块包含不紧密的职责,则修改成本可能会很高。将模块重构为几个更紧凑的模块应该可以降低未来变更的平均成本。拆分模块不应简单地将一半的代码行放入每个子模块中;相反,它应该明智而适当地产生一系列相互紧凑的子模块。

  • 重新分配职责。如果职责 A、A′ 和 A“(所有类似的职责)分布在几个不同的模块中,则应将它们放在一起。这种重构可能涉及创建新模块,或者可能涉及将职责转移到现有模块。确定要移动的职责的一种方法是假设一组可能的变更作为情形。如果情形中始终只影响模块的一部分,那么其他部分可能具有单独的职责,应该移动。或者,如果某些情形需要修改多个模块,则可能应将受影响的职责分组到一个新模块中。

降低耦合

我们现在转向减少模块之间耦合的策略。这些策略与 第7章 中描述的可集成性策略重叠,因为减少独立组件之间的依赖性(对于可集成性)类似于减少模块之间的耦合(对于可修改性)。

  • 封装。请参阅 第7章 中的讨论。

  • 使用中介。请参阅 第7章 中的讨论。

  • 抽象公共服务。请参阅 第7章 中的讨论。

  • 限制依赖关系。 此策略限制给定模块与哪些模块交互或依赖哪些模块。在实践中,这种策略是通过限制模块的可见性(当开发人员看不到接口时,他们就没法使用它)和授权(限制对仅授权模块的访问)来实现的。限制依赖策略见于分层架构,其中一层只允许使用较低层(有时只允许使用下一个较低层),并且使用包装器,其中外部实体只能看到(因此依赖于)包装器,而不是它包装的内部功能。

延迟绑定

因为人们的工作几乎总是比计算机的工作更昂贵,更容易出错,所以让计算机尽可能多地处变更几乎总是会降低进行变更的成本。如果我们设计具有内置灵活性的工件,那么行使这种灵活性通常比手动编码特定变更更经济。

参数也许是引入灵活性的最著名机制,它们的使用让人想起抽象公共服务策略。参数化函数 fab) 比假设 b = 0 的类似函数 fa) 更通用。当我们在生命周期中的另外一个阶段绑定某些参数的值,而不是在定义参数的阶段绑定它们时,我们正在使用延迟绑定。

一般来说,在生命周期中,我们可以绑定值的越晚越好。然而,建立机制以促进后期绑定往往更昂贵——这是一个众所周知的权衡。因此,本章前面给出的等式开始发挥作用。我们希望尽可能晚地绑定,只要允许它的机制具有成本效益。

以下策略可用于在编译时或生成时绑定值:

  • 组件替换(例如,在生成脚本或生成文件中)

  • 编译时参数化

  • 切面

以下策略可用于在部署、启动时或初始化时绑定值:

  • 配置时绑定

  • 资源文件

在运行时绑定值的策略包括:

  • 发现(见第7章

  • 解释参数

  • 共享存储库

  • 多态性

将构建可修改性机制与使用该机制进行修改分开,从而让不同利益相关者有参与的可能性 —— 一个利益相关者(通常是开发人员)提供该机制,另一个利益相关者(管理员或安装人员)稍后执行该机制,它们可能发生在完全不同的生命周期阶段。安装一种机制,以便其他人可以在不必更改任何代码的情况下对系统进行更改,有时称为 外部化 变更。

8.3 基于策略的可修改性问卷

根据 8.2节 中描述的策略,我们可以创建一组受策略启发的问题,如 表8.2 所示。为了大致了解为支持可修改性而做出的架构选择,分析师会询问每个问题并将答案记录在表中。然后,可以将这些问题的答案作为接下来工作的重点:文档调查、代码或其他工件分析、代码逆向工程等。

表8.2 基于策略的可修改性调查表

策略组策略问题支持与否(是/否)风险设计决策和位置原因和假设
增加内聚你是否通过拆分模块使模块更具凝聚力?例如,如果你有一个大而复杂的模块,你能把它分成两个(或更多)更内聚的模块吗?
你是否通过重新分配职责使模块更具内聚力?例如,如果模块中的职责没有相同的目的,则应将它们放在其他模块中。
降低耦合你是否始终如一地封装功能?这通常涉及隔离受审查的功能并为其引入显式接口。
你是否始终使用中介来防止模块耦合得太紧密?例如,如果 A 调用具体功能 C,则可以引入在 A 和 C 之间作为中介的抽象B。
你是否以系统的方式限制模块之间的依赖关系?或者是否有任何系统模块可以自由地与任何其他模块交互?
减少耦合在你提供几种类似服务的情况下,你是否抽象共同服务?例如,当你希望系统可跨操作系统、硬件或其他环境变化进行可移植时,通常会使用此技术。
延迟绑定系统是否有规律地 延迟绑定 重要功能,以便在生命周期的后期可以替换它?例如,是否有可以扩展系统功能的插件、附加组件、资源文件或配置文件?

8.4 模式

可修改性模式将系统划分为模块,这样模块就可以单独开发和演变,而它们之间几乎没有交互,从而支持可移植性、可修改性和重用。与任何其他质量属性相比,设计用于支持可修改性的模式可能更多。我们介绍一些这里最常用的方法。

客户端-服务器模式

客户端-服务器模式由同时向多个分布式客户端提供服务的服务器组成。最常见的示例是 Web 服务器向网站的多个同时用户提供信息。

服务器与其客户端之间的交互遵循以下顺序:

  • 发现:

    • 通信由客户端启动,客户端使用发现服务来确定服务器的位置。

    • 服务器使用商定的协议响应客户端。

  • 交互:

    • 客户端向服务器发送请求。

    • 服务器处理请求并作出响应。

关于这个次序有几点值得注意:

  • 如果客户端数超过单个服务器实例的容量,则服务器可能有多个实例。

  • 如果服务器相对于客户端是无状态的,则来自客户端的每个请求都将被单独处理。

  • 如果服务器维护与客户端相关的状态,则:

    • 每个请求都必须以某种方式标识客户端。

    • 客户端应发送“会话结束”消息,以便服务器可以删除与该特定客户端关联的资源。

    • 如果客户端在指定时间内未发送请求,则服务器可能会超时,以便可以删除与客户端关联的资源。

好处:

  • 服务器与其客户端之间的连接是动态建立的。服务器对其客户端没有先验知识,也就是说,服务器与其客户端之间的耦合度较低。

  • 客户端之间没有耦合。

  • 客户端的数量可以轻松扩展,并且仅受服务器容量的限制。如果超出其容量,服务器功能也可以扩展。

  • 客户端和服务器可以独立演讲。

  • 公共服务可以在多个客户端之间共享。

  • 与用户的交互是与客户端隔离的。这一因素导致了用于管理用户界面的专用语言和工具的开发。

权衡:

  • 此模式的实现使得通信通过网络(甚至可能是 Internet)进行。因此,消息可能会因网络拥塞而延迟,从而导致性能下降(或是至少不可预测的)。

  • 对于通过其他应用程序共享的网络与服务器通信的客户端,必须为实现信息安全性(尤其是保密性)和维护完整性做出特殊规定。

插件(微内核)模式

插件模式有两种类型的元素:提供一组核心功能的元素和通过一组固定接口向核心添加功能的专用变体(称为插件)。这两种类型通常在生成时或以后绑定在一起。

用法示例包括以下情况:

  • 核心功能可能是精简的操作系统(微内核),它提供实现操作系统服务所需的机制,例如低级地址空间管理、线程管理和进程间通信 (IPC)。这些插件提供实际的操作系统功能,例如设备驱动程序、任务管理和 I/O 请求管理。

  • 核心功能是向用户提供服务的产品。插件提供可移植性,例如操作系统兼容性或支持库兼容性。插件还可以提供核心产品中未包含的其他功能。此外,它们可以充当适配器以实现与外部系统的集成(参见 第7章)。

好处:

  • 插件提供了一种受控机制来扩展核心产品,并使其在各种上下文中有用。

  • 插件可以由与微内核开发人员不同的团队或组织开发。这允许开发两个不同的市场:核心产品和插件。

  • 插件可以独立于微内核演讲。由于它们通过固定接口进行交互,因此只要接口不更改,这两种类型的元素就不会以其他方式耦合。

权衡:

  • 由于插件可以由不同的组织开发,因此更容易引入安全漏洞和隐私威胁。

分层模式

分层模式以这样一种方式划分系统,即模块可以单独开发和演进,部件之间几乎没有交互,这支持可移植性、可修改性和重用性。为了实现这种关注点分离,分层模式将软件划分为称为层的单元。每一层都是一组模块,提供一组内聚的服务。层之间的 允许使用 关系受关键约束的限制:关系必须是单向的。

层完全分区一组软件,每个分区通过公共接口公开。层以根据严格的排序关系进行交互来创建。如果(A,B)处于这种关系中,我们说分配给A层的软件被允许使用B层提供的任何公共设施(在几乎无处不在的垂直排列的层表示中,A将被绘制得高于B。在某些情况下,一层中的模块需要直接使用不相邻的下层中的模块,尽管通常只允许下一层使用。这种在较高层使用不相邻的较低层中的模块的软件的情况称为 层桥接。在此模式中不允许向上使用。

好处:

  • 由于上层被限制为仅使用较低层,因此可以更改较低层中的软件(只要接口不更改),而不会影响上层。

  • 较低级别的层可以在不同的应用程序中重用。例如,假设某个层允许跨操作系统的可移植性。此层在必须在多个不同操作系统上运行的任何系统中都很有用。最底层通常由商业软件提供,例如操作系统或网络通信软件。

  • 由于受到允许使用 关系的约束,因此任何团队都必须了解的接口数量都会减少。

权衡:

  • 如果分层设计不正确,它实际上可能会妨碍为上层提供所需的底层抽象。

  • 分层通常会给系统增加性能损失。如果调用是从最顶层的函数进行的,则在硬件执行之前,它可能必须经过许多较低层。

  • 如果发生许多层桥接实例,系统可能无法满足其可移植性和可修改性目标,而严格的分层有助于实现这些目标。

发布-订阅模式

发布-订阅是一种架构模式,其中组件主要通过异步消息(有时称为“事件”或“主题”)进行通信。发布者不知道订阅者,订阅者只知道消息类型。使用发布-订阅模式的系统依赖于隐式调用;也就是说,发布消息的组件不会直接调用任何其他组件。组件发布有关一个或多个事件或主题的消息,其他组件注册对发布的兴趣。在运行时,当发布消息时,发布-订阅(或事件)总线会通知在事件或主题中注册感兴趣的所有元素。这样,消息发布会导致对其他组件(方法)的隐式调用。结果是发布者和订阅者之间的松散耦合。

发布-订阅模式有三种类型的元素:

  • 发布者组件。发送(发布)消息。

  • 订阅者组件。订阅然后接收消息。

  • 事件总线。将订阅和消息调度作为运行时基础设施的一部分进行管理。

好处:

  • 发布者和订阅者是独立的,因此是松散耦合的。添加或更改订阅者只需要注册事件,并且不会对发布者造成任何更改。

  • 通过更改正在发布的消息的事件或主题,以及哪些订阅者可能接收并处理此消息,可以轻松更改系统行为。这个看似很小的更改可能会产生巨大的后果,因为可以通过添加或禁止显示消息来打开或关闭功能。

  • 可以轻松记录事件以允许记录和回放,从而重现手动重新创建可能具有挑战性的错误条件。

权衡:

  • 某些发布-订阅模式的实现可能会对性能(延迟)产生负面影响。使用分布式协调机制将改善性能下降的问题。

  • 在某些情况下,组件无法确定接收已发布消息需要多长时间。通常,在发布-订阅系统中,系统性能和资源管理更难推断。

  • 使用此模式可能会对同步系统的确定性产生负面影响。由于事件,调用方法的顺序在某些实现中可能会有所不同。

  • 使用发布-订阅模式可能会对可测试性产生负面影响。事件总线中看似很小的更改(例如,更改哪些组件与哪些事件相关联)可能会对系统行为和服务质量产生很大的影响。

  • 某些发布-订阅实现限制了可用于灵活实现信息安全性(完整性)的机制。由于发布者不知道其订阅者的身份,反之亦然,因此端到端加密受到限制。从发布者到事件总线的消息可以唯一加密,从事件总线到订阅者的消息可以唯一加密;但是,任何端到端加密通信都要求所涉及的所有发布者和订阅者共享相同的密钥。

扩展阅读

认真研究软件工程及其历史的学生应该阅读两篇关于可修改性设计的早期论文。第一篇是 Edsger Dijkstra 1968 年关于 T.H.E. 操作系统的论文,这是第一篇讨论设计使用层的系统以及这种方法带来的可修改性好处的论文 [Dijkstra 68]。第二个是大卫·帕纳斯(David Parnas)1972年的论文,该论文引入了信息隐藏的概念。[Parnas 72] 建议定义模块不是通过其功能,而是通过它们内化更改效果的能力。

更多可修改性的模式在 软件系统架构:使用视点和视角与利益相关者合作 [Woods 11] 中给出。

解耦级别指标 [Mo 16] 是一个架构级耦合指标,可以深入了解架构的全局耦合程度。这些信息可用于跟踪一段时间内的耦合,作为技术债务的早期预警指标。

[Mo 19] 中描述了一种检测模块化违规和其他类型的设计缺陷的全自动方法。检测到的违规可以作为重构的指南,从而增加内聚力并减少耦合。

用于软件产品线的软件模块通常充满了变化机制,允许它们快速修改以服务于不同的应用程序,即产品线的不同成员。产品线中组件的变化机制列表可以在Bachmann和Clements[Bachmann 05],Jacobson及其同事[Jacobson 97]和Anastasopoulos及其同事[Anastasopoulos 00]的作品中找到。

分层模式有多种形式和变体,例如“带有挎斗(sidecar)的分层”。[DSA2]的第2.4节将它们全部整理出来,并讨论了为什么(令人惊讶的是,对于半个多世纪前发明的架构模式)你见过的大多数软件分层图都非常模糊。如果你不想读这本书,那么[Bachmann 00a]是一个很好的替代品。

8.6 问题讨论

1. 可修改性有多种风格,并以许多名称而闻名;我们在本章的开头部分讨论了一些,但这些讨论只是触及了表面。找到一个处理质量属性的IEEE或ISO标准,并编制一个质量属性列表,这些属性指的是某种形式的可修改性。讨论差异。

2. 在你为问题1编制的列表中,哪些策略和模式对每个都特别有用?

3. 对于你在问题 2 中发现的每个质量属性,请编写一个表示该属性的可修改性方案。

4. 在许多自助洗衣店,洗衣机和烘干机接受硬币,但不找零。取而代之的是,由单独的机器换币。在普通自助洗衣店中,每台换币机都有六到八台洗衣机和烘干机。你认为在这种安排中有哪些可修改性策略在起作用?关于可用性,你能说些什么?

5. 对于问题4中的自助洗衣店,描述可修改性的具体形式(使用可修改性情形),这似乎是按照所述安排机器的目的。

6.第 7 章 中引入的 包装器 是一种常见的架构模式,用于帮助可修改性。包装器体现了哪些可修改性策略?

7. 其他可以提高系统可修改性的常见架构模式包括黑板、代理、点对点、模型-视图-控制器和反射。根据其打包的可修改性策略讨论每个策略。

8. 一旦中介被引入到架构中,一些模块可能会试图绕过它,无论是无意的(因为它们不知道中介)还是故意的(为了性能、为了方便或出于习惯)。讨论一些架构方法,以防止对中介的不良规避。还要讨论一些非架构方法。

9. 抽象的公共服务策略旨在减少耦合,但也可能减少内聚。进行讨论。

10. 讨论客户端-服务器模式是具有运行时绑定的微内核模式的命题。


  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值