设计模式与软件体系结构期末复习笔记
设计模式与软件体系结构期末复习笔记
创建型
简单工厂模式
简单工厂模式:又称为静态工厂方法模式。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。
简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
违背了开闭原则
工厂方法模式
将简单工厂方法模式中单一的工厂类改写为一个层次类
每个产品类对应于一个工厂类。该工厂类只负责创建相应的产品类的对象。
客户端调用创造类和产品类,所有的产品由所属的创造类创造,
符合开闭原则
抽象工厂模式
抽象工厂模式可能符号开闭原则也可能不符合
抽象工厂模式不直接创建具体的对象,而是提供一个抽象的接口来创建一整套(或“家族”)相关或依赖的对象。客户端代码只与这些抽象接口打交道,从而实现与具体产品类和具体工厂类的解耦。
客户端只调用抽象工厂,抽象工厂创造不同的工厂,由被创造的工厂生成产品类
生成器模式
生成器模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
在生成器模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
每一个具体生成器都相对独立,而与其他的具体生成器无关,因此可以很方便地替换具体生成器或增加新的具体生成器,用户使用不同的具体生成器即可得到不同的产品对象。
可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
增加新的具体生成器无须修改原有类库的代码,指挥者类针对抽象生成器类编程,系统扩展方便,符合“开闭原则”。
单例模式
单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供一个全局访问点。
基本思路
将构造方法声明为private类型,其他类无法使用该构造方法来创建对象
提供一个可以获得实例的getInstance方法,该方法是静态方法,确保客户程序得到的始终是同一个对象
结构型
组合模式将一个或者多个相似的对象构成组合对象。
适配器模式提供一种机制改变原来不适合使用的接口。
外观模式新建一个外观类,通过调用原有的类库中众多的类的方式,实现外观类的所有方法。
组合模式
组合多个对象形成树形结构以表示“整体-部分”的结构层次。
透明形式的组合模式:在Component类中声明所有的用来管理子类对象的方法,包括add( )、remove( ),以及getChild( )方法。
优点:所有的构件类都有相同的接口;
缺点:不够安全。
Component:为组合模式中的对象声明接口
Leaf:在组合模式中表示叶结点对象
Composite:表示组合部件
Client:通过Component接口操纵组合部件的对象。
优点:
可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。
客户端调用简单,客户端可以一致地使用组合结构或其中单个对象。
定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。
在组合体内加入对象构件更容易,客户端不必因为加入了新的对象构件而更改原有代码。
适配器模式
在软件开发中,为了解决接口不一致的问题,两个软件模块之间往往也需要通过一个适配器类Adapter进行“适配”。这样的模式叫做适配器设计模式。
类适配器
方案:用一个Target接口声明所有需要的方法,并且用另外一个Adapter类实现Target接口中所有的方法。同时,Adapter类继承Adaptee类。
对象适配器
在Java语言中不允许有多继承,所以,如果同时有两个或者两个以上的类Adaptee1、Adaptee2需要被适配,则不能够继续使用类适配器模式进行设计,
适配器优点:
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
外观模式
外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式也是“迪米特法则”的体现,通过引入一个新的外观类可以降低原有系统的复杂度,同时降低客户类与子系统类的耦合度。
外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。
外观模式与适配器模式的区别:
特性 | 外观模式(Facade Pattern) | 适配器模式(Adapter Pattern) |
---|---|---|
目的 | 简化复杂子系统的使用,提供统一的高层接口,隐藏内部细节。 | 解决接口不兼容问题,使原本不兼容的类能够协同工作。 |
关注点 | 简化和统一。 | 转换和兼容。 |
作用对象 | 一个或多个子系统(Many-to-One)。 | 一个现有类(被适配者)到目标接口(One-to-One)。 |
接口关系 | 提供一个新的、更高级别的接口,它聚合并调用子系统方法。 | 将一个现有接口转换成另一个期望的接口。 |
解决问题 | 客户端与复杂子系统之间的高耦合和使用复杂性。 | 接口不兼容,导致现有代码无法复用。 |
方向 | 从多个低层接口到一个高层接口。 | 从一个旧接口到一个新接口。 |
类比 | 家庭影院遥控器的“观看电影”按钮。 | 电源转换插头、USB转PS/2接口。 |
桥接模式
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。
它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。
优点:
- 分离抽象接口及其实现部分。
- 桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差,而且多继承结构中类的个数非常庞大,桥接模式是比多继承方案更好的解决方法。
- 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
- 实现细节对客户透明,可以对用户隐藏实现细节。
缺点:
- 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
行为性
迭代器模式
在迭代器模式中,提供一个外部的迭代器来对聚合对象进行访问和遍历,
迭代器定义了一个访问该聚合元素的接口,并且可以跟踪当前遍历的元素,了解哪些元素已经遍历过而哪些没有。
优点:
- 迭代器模式支持以不同的方式遍历同一个聚合,复杂的聚合可用多种方式进行遍历。
- 满足“开闭原则”的要求。
- 迭代器简化了聚合的接口。有了迭代器的遍历接口,聚合本身就不需要类似的遍历接口了,这样就简化了聚合的接口。
访问者模式
访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式
优点:
- 使得增加新的访问操作变得很容易。
- 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散到一个个的元素类中。
- 可以跨过类的等级结构访问属于不同的等级结构的元素类。
- 让用户能够在不修改现有类层次结构的情况下,定义该类层次结构的操作。
缺点:
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求。
- 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。
中介者模式
用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
中介者模式的要点是将所有对象之间的交互细节抽象到一个独立的类中,这个类叫做中介者类Mediator
优点:
- 所有对象的交互行为都被转入到一个独立的中介者对象中,使得用户更容易通过中介者修改对象之间的相互关系行为。当修改一个交互行为的时候,可以通过修改或者更换其中一个具体的中介者子类来完成。简化了对象之间的交互。另外,将对象的交互转移到一个专门的类中也提高了对象的可重用性。
- 因为对象之间不直接有交互,使对象的单元测试更加容易。
- 低耦合使得一个类的修改不会影响到其他的类。可以简化各同事类的设计和实现。
缺点:
在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。
策略模式
策略模式定义了一系列算法,将每一个算法封装起来,并且使它们之间可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。
策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
优点:
- 得到一系列可以复用的算法,这些算法继承一个共同的抽象类,因此共有的功能可以放到超类中;
- 将不同算法封装在不同的策略子类中,使逻辑更加清晰,各个算法可以独立地变化;
- 使功能改变或者扩展更容易,修改一个算法不必重新编译“Client”与“Context”。
缺点:
客户程序必须知道不同策略接口的各个子类的行为,必须理解每个子类有哪些不同。因此,在客户类中通常存在许多与策略类各个分支相关的条件语句,用于选择产生策略子类对象,然后将这些对象传递给Context类,而Context类则直接使用此对象调用策略模式的策略子类的方法。
状态模式
与策略模式类似,状态模式将不同状态下的行为封装在不同的类中,每个类代表一个状态。
策略模式和状态模式的相似之处
两种模式在结构上是相同的。策略模式将每个条件分支封装在一个子类中,而状态模式将每个状态封装在一个子类中。
策略模式和状态模式的区别
策略模式用来处理一组具有相同目的但是实现方法不同的算法,这些算法方案之间一般来说没有状态变迁,并且用户总是从几个算法中间选取一个。
状态模式则不同,它实现的一个概念可以叫做动态继承,也就是继承的子类都可以发生变化。状态的变化可以由一个状态迁徙图表示。
经典软件体系结构
调用-返回风格软件体系结构
其主要思想是:将一个复杂的大系统分解为一些子系统,以便降低复杂度,并且增加可修改性。
调用-返回风格体系结构可以被组织成任何形式。但层次结构的组织形式更清晰
层次结构
层次结构的设计被称为共享数据的主程序-子程序软件体系结构
结构化程序
自顶向下功能化设计方法(结构化程序设计)的设计思想是:系统从功能的角度进行设计,从高层开始,逐步细化为详细设计。
自顶向下的设计方法的问题
- 功能演化困难
- 现实中的系统功能不容易描述
- 功能化设计丢掉了数据与数据结构。
- 由功能设计得到的软件产品产生的可复用的代码较少。
结构化设计的优缺点
优点
- 逻辑设计与物理设计分离
- 开发过程中形成一套规范化的文档,便于将来修改和维护
缺点
- 开发周期长,开发过程复杂
- 系统难于适应环境变化
- 经验表明,较小的程序(小于10万行)适合于结构化开发
面向对象体系结构
特点:
- 封装性
- 继承性
- 多态
- 复用和可维护性
- 对象是对现实世界的抽象并且可以管理自己
- 系统功能通过对象服务表示
- 共享数据区域被取消
- 对象可以是分布式的
优点
- 容易维护:因为一个对象将其内部表示对客户程序隐藏起来,所以可以改变其内部实现而不影响那些客户程序。
- 可复用性好:对象为适合复用的构件。
- 映射现实世界:对于许多软件系统都存在明显的现实世界的实体到系统的对象。
- 容易对一个系统进行剖分:面向对象设计将数据与数据访问、操纵方法绑定在一起形成类,由类产生对象。使得软件设计者将整个问题剖分为一系列的互相交互的对象的集合。
缺点:
- 面向对象程序占用内存较大。这是因为在程序运行中,每个新被创建的对象都必须占用一块内存,而在面向对象程序中,往往有大量的对象被创建。
- 一个对象要和另外一个对象交互,该对象必须知道另外一个对象的身份,包括对象名、方法名和参数类型等。
数据流风格软件体系结构
数据流系统是一个软件系统,在该系统中,数据的可用性控制计算,过程间的数据有序流动决定了系统的结构。数据的流动方式是明确的。
批处理
特点
- 每个处理程序模块都是互为独立的程序。
- 只有上一步程序彻底完成了,下一步程序才能开始。
- 数据作为一个整体进行传输。
- 因为以上的特点,所以不必对其组件进行同步处理。
- 因为几个组件只能按照顺序运行,而不能同步运行,所以性能可能比那些能按照几个组件同时运行的程序要差一些。
- 使用顺序批处理结构设计的软件不适用于要求对数据进行实时处理的系统。
管道-过滤器
管道和过滤器优点:
- 使得软构件具有良好的隐蔽性和高内聚、低耦合的特点;
- 允许设计者将整个系统的输入/输出行为看成是多个过滤器的行为的简单合成;
- 支持软件复用。只要提供适合在两个过滤器之间传送的数据,任何两个过滤器都可被连接起来;
- 系统维护和增强系统性能简单。新的过滤器可以添加到现有系统中来;旧的可以被改进的过滤器替换掉;
- 允许对一些如吞吐量、死锁等属性的分析
- 支持并行执行。
控制
不知道,开摆
基于事件的软件体系结构
如果一个系统的组件提供了一组子程序或者方法,其中的一个子程序调用其他子程序,并准确知道该子程序的名字,包括参数与返回值等,则说这种调用是显式调用。
系统中的其它构件中的过程在一个或多个事件中注册,当一个事件被触发,系统自动调用在这个事件中注册的所有过程,这样,一个事件的触发就导致了另一模块中的过程的调用。这种调用称为隐式调用。
事件派遣模块
事件派遣模块的功能:
负责接收到来的事件并派遣它们到其他模块。
派遣器决定派遣方式,有两种派遣方式:
广播式:派遣模块将事件广播到所有的模块,但只有感兴趣的模块才去取事件,并触发自身的行为;广播式有两种策略,Point-to-Point(点对点模式):基于消息队列和Publish-Subscribe(发布-订阅模式)
选择广播式:派遣模块将事件送到那些已经注册了的模块中。
无独立调度模块的事件系统
这种模式称为“被观察者/观察者”。
每一个模块都允许其他模块向自己所发送的某些消息表明兴趣。
当某一模块发出某一事件时,它自动将这些事件发布给那些曾经向自己注册过此事件的模块。
层次软件体系结构
有两种通用的分层方法:
严格分层(Strict System Layering)
松散分层(Loosely System Layering)
严格分层系统要求严格遵循分层原则,限制一层中的构件只能与对等实体以及与它紧邻的下面一层进行交互。
松散的分层应用程序放宽了此限制,它允许构件与位于它下面的任意层中的组件进行交互
针对分层系统中各层次之间如何交互,分为以下两种基本的交互方式:
由上而下的交互方式 (top-down triggering)
由下而上的交互方式 (bottom-up triggering)
在由上而下模式中,外部实体与系统中的最高层交互。
在由下而上模式中,外部实体与系统中的最底层交互,通常用来监视某些底层系统的状态变化。
层次软件体系结构的三个典型应用。
答:层次通信协议,数据库系统领域,操作系统领域
MVC软件体系结构
MVC体系结构将一个互动的应用分为三部分:Model、View、Controller。Model包含核心功能与数据,View为用户显示信息,Controller处理用户输入。
基于网络的软件体系结构
客服端-服务端软件体系结构
C/S体系结构有三个主要组成部分:服务器、客户应用程序、网络。
业务逻辑的划分比重:在客户端多一些还是在服务器多一些?
胖客户端:客户端执行大部分的数据处理操作
瘦客户端:客户端具有很少或没有业务逻辑
一层客户端-服务器:终端设备直接与大型机相连
二层客户端-服务器:使用SQL实现客户端和服务器之间的通信
三层客户端-服务端:客户端-应用服务器-数据库服务器
三层层次体系结构与三层客户端-服务器软件体系结构的主要区别是:
在通常的层次体系结构中所涉及的层次指的是逻辑层,而三层客户端-服务器体系结构中所涉及的层是从物理方面考虑的层。
即客户端运行在PC上,服务层被部署在应用服务器上,数据库层包含数据库与数据库管理系统软件,被部署在数据库服务器上。
P2P软件体系结构
任何一个结点都可以请求服务和提供服务,也就是说每个结点都是客户端,也是服务器。
第一代:集中目录式
目录服务器形式上是该对等网络的“中心”。但是,实际上目录服务器除了提供各结点的基本的已注册信息之外,并不真正地承担任何其他的功能,因此,该体系结构与传统的客户端 – 服务器体系结构还是有本质的区别。
缺点:网络的稳定性较差。一旦服务器失效,则该服务器下的对等结点可能全部失效。
第二代:纯P2P体系结构也被称为广播式的P2P模型,它没有集中的中央目录服务器,每个用户随机接入网络,并与自己相邻的一组邻居结点通过端到端连接构成一个逻辑覆盖的网络。
纯P2P网络结构解决了网络结构中心化的问题,扩展性和容错性较好。
纯P2P体系结构具有如下缺点:
服务发现限制与困难。在大型P2P网络中,查询会遇到查询范围小的困难。
由于没有一个对等结点知道整个网络的结构,网络中的搜索算法以泛洪的方式进行,控制信息的泛滥消耗了大量带宽并且可能很快造成网络拥塞甚至网络的不稳定,从而导致整个网络的可用性较差。
系统容易受到垃圾信息,甚至是病毒的恶意攻击。
第三代:基于层次的第三代P2P系统。通过将对等结点分为超级结点与叶子结点两大类的方法,让超级结点形成一个建立在原来的对等网络之上的覆盖网络的方式,引入了层次的概念。
网格计算软件体系结构
网格计算(Grid Computing)的软件体系结构是其核心,它旨在将地理上分散、异构的计算资源(如服务器、存储设备、网络带宽、科学仪器等)整合成一个统一的、可共享的虚拟计算平台,为用户提供透明、按需的计算能力。
网格计算的工作原理为,使用中间件将计算任务分成许多子任务,然后分派到不同的计算机上同时进行运算。
目前最常使用的网格主要有以下三种。
- 计算网格:计算网格是各个结点都有计算与处理能力的网格。这是最为常见的网格类型,它已被成功地用于执行一些计算密集型的任务。
- 数据网格:数据存储是数据网格的主要共享资源。这样的网格可被认为是集成了大量的存储设备而形成的巨大的数据存储系统。
- 网络网格:网络网格的主要目的是提供容错和高性能的通信服务。在这种网格中,每个网格结点在两个通信结点之间像数据路由器一样工作,提供数据缓存和其他的设施,以加速数据在通信结点的传输。
网格计算与P2P计算的比较
- 网格计算强调资源整合、性能、服务质量和安全性等问题。
- P2P计算关注网络服务质量和支持问题。
SOA软件体系结构与Web Service
需要实现服务的自动发现、动态绑定、自动执行等特性。因此需要一种新的体系结构,这就是SOA体系结构。
在SOA体系结构中,服务提供者与消费者之间不是静态绑定的,而是可以被自动发现和动态绑定的。
SOA体系结构的特点:
- 服务是可以被发现和动态绑定的。
- 服务是自我包含与模块化的。
- 服务是松散耦合的。
- 服务有一个网络可寻址的端口。
- 服务是地点透明的。
- 服务是面向组合的。
Web Service 就是SOA体系结构的一种实现
Web Service提供了一种在异构应用之间进行交互操作的标准方案。
Web Service的工作原理:
- 服务提供者创建并且发布服务描述信息到服务注册器。服务提供者需要决定哪些服务暴露给服务消费者,如何在安全性与易可用性之间进行折中,怎样为每项服务定价等。服务注册器提供了可供服务的列表,服务注册器扮演了中介人的角色,而且该角色可以是私有的,也可以是公开的。
- 服务消费者可通过服务中介所提供的服务列表发现需要的服务,并且绑定相应的服务提供者。一旦选中了中介者提供的列表中的某项服务,必须通知中介者,接下来可以绑定该项服务。如果服务提供者提供了多项服务,消费者可以一次使用多项服务。
云计算
服务模型
- 基础设施即服务(IaaS):该模式的云服务,提供处理器、存储、网络和其他基本计算资源的租用服务,允许消费者在其上部署、运行任意软件。
- 平台即服务(PaaS):该模式的云服务,提供指定类型应用的托管服务,消费者可以把用指定语言编写的程序创建和部署在云上。
- 软件即服务(SaaS):该模式的云服务,提供在云基础设施上运行的、由提供者创建的应用服务。这些应用可以被不同客户端设备访问、配置和使用,而应用的用户则不直接管理或控制包括网络、服务器、操作系统和存储等在内的底层云基础设施。
参考