软件设计模式与体系结构(上)

软件设计模式概述(面向对象设计概述)

一、面向对象设计的表示方法

1. UML

  • 类(Class)封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性、操作、关系的对象集合的总称。

类之间的关系:

  • 关联直线箭头在这里插入图片描述

  • 聚合/组合聚合:总体的一侧为空菱形,部分的一侧为箭头 组合:总体的一侧为实菱形,部分的一侧为箭头在这里插入图片描述

关联和聚合的区别主要在语义上,关联的两个对象之间一般是平等的,例如你是我的朋友,聚合则一般不是平等的,例如一个公司包含了很多员工,其实现上是差不多的。

  • 泛化空三角+实线在这里插入图片描述在这里插入图片描述

几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖
参考:关联、聚合、组合的区别

  • 接口和实现 在这里插入图片描述在这里插入图片描述

  • 其他辅助视图

在这里插入图片描述在这里插入图片描述

好的系统设计应该具有的三个性质:
1.可扩展性
2.灵活性
3.可插拔性
在这里插入图片描述
重构(Refactoring)是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量、性能,使其程序设计模式和架构更趋合理,提高软件的扩展性和维护性

二、面向对象的设计原则

在这里插入图片描述

在这里插入图片描述

记忆口诀:访问加限制,函数要节俭,依赖不允许,动态加接口,父类要抽象,扩展不更改。

1.单一原则

  • 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中
  • 一个类(或者大到模块,小到方法)承担的职责过多,它被复用的可能性越小。
  • 单一职责原则是实现高内聚、低耦合的指导方针

在这里插入图片描述
在这里插入图片描述

2.开闭原则

  • 一个软件实体应当对扩展开放,对修改关闭
  • 开闭原则还可以通过一个更加具体的“对可变性封装原则”来描述

对于扩展时开放的:可以对模块进行扩展,增加新的功能
对于修改时封闭的:在对模块行为进行扩展时,不允许改动块中已经存在的类的源代码

在这里插入图片描述
在这里插入图片描述

3.里氏代换原则

  • 第一种定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型
  • 第二种定义:所有引用基类(父类)的地方必须能透明地使用其子类的对象

因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象
子类可扩展父类的方法属性,但不能修改

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

4.依赖倒转原则

  • 定义:
    • 高层模块不应该依赖低层模块,它们都应该依赖抽象
    • 抽象不应该依赖于细节
    • 细节应该依赖于抽象
    • 另一种表述为:要针对接口编程,而不是针对实现编程

在这里插入图片描述
在这里插入图片描述

JAVAEE中有提到过

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.接口隔离原则

  • 定义:客户端不应该依赖那些它不需要的接口
  • 另一种定义:一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.合成复用原则

又称为组合/聚合复用原则

  • 定义:
    • 尽量使用对象组合,而不是继承来达到复用的目的
    • 合成复用原则就是指在一个新的对象里通过组合关系和聚合关系来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用其已有功能的目的
  • 简而言之,要尽量使用组合/聚合关系,少用继承

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

7.迪米特法则

定义:

  • 不要和“陌生人”说话
  • 只与你的直接朋友通信
  • 每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位
  • 简单地说,迪米特法则就是指一个软件实体应当尽可能少的与其他实体发生相互作用在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建型软件设计模式

模式包括:
1.模式的名称
2.模式的目的,即要解决的问题
3.实现方法
4.为实现该模式必须考虑的限制和约束因素

设计模式的分类
根据其目的(模式是用来做什么的),面向对象的领域的设计模式可分为创建型(Creational),==结构型(Structural)行为型(Behavioral)==三种:

  1. 创建型模式主要用于创建对象
  2. 结构型模式主要用于处理类或对象的组合
  3. 行为型模式主要用于描述对类或对象怎样交互和怎样分配职责

创建型模式两个主导思想:

  1. 封装了系统使用的具体类的知识
  2. 隐藏这些具体类的实例被创建与结合的细节

目标

  • 其目的是在哪个对象被创建、谁负责创建对象、怎样创建对象、何时创建对象等方面增强灵活性。
    内容
  • 创建型软件设计模式是解决对象创建机制的设计模式。

一、工厂方法与抽象工厂模式

工厂方法的优点:

  • 使用工厂方法访问并初始化合适的类的对象,简化了应用程序,应用程序本身不再含有大量的条件语句判定何时选取哪个类
  • 工厂方法实现了一些特殊的初始某个类的机制,尤其是层次结构不同的类需要不同的初始化方法的时候
  • 工厂方法返回一个父类的对象,客户程序不必知道这个被初始化的类的存在

工厂方法设计模式被分为:简单工厂方法模式工厂方法模式抽象工厂模式等几种情况。

1.简单工厂方法模式

简单工厂模式:又称为静态工厂方法模式
在简单工厂模式中,可以根据参数的不同返回不同类的实例
简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类
在这里插入图片描述
优点
1.实现了对责任的分割,它提供了专门的工厂类用于创建对象
2.客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可
3.通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类
缺点
1.由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响
2.增加系统中类的个数
3.系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时
4.工厂角色无法形成基于继承的等级结构

简单工厂模式最大的缺点就是当有新产品要加入到系统中时,必须修改工厂类,加入必要的处理逻辑,这违背了“开闭原则”

适用环境
在这里插入图片描述

2.工厂方法模式

将简单工厂方法中单一的工厂类改写为一个层次类

工厂类+产品类
在这里插入图片描述

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做
工厂方法模式退化后可以演变成简单工厂模式

优点:
1.用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名
2.工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部
3.在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。
缺点:
1.在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
2.增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

在这里插入图片描述
简单工厂模式的中心为一个实的工厂类,工厂方法模式的中心为抽象工厂或者接口
简单工厂模式不支持开闭原则,而工厂模式支持
简单工厂模式中,必要的创建对象的逻辑判断包含在工厂类中(看教材p11的PolicyProducer),在工厂方法模式中,工厂类不必包含创建对象的逻辑判断

工厂方法模式的适用场景
在这里插入图片描述

3.抽象工厂模式

两个概念
在这里插入图片描述在这里插入图片描述
例如:
在这里插入图片描述

开闭原则情况:
1.符合
在这里插入图片描述
2.不符合
就是增加一个新的种类产品
在这里插入图片描述

例如原来有两家公司A和B生产电视和冰箱,现在增加一个公司C也生产电视和冰箱则符合开闭原则
但如果是让原来的A和B新增加生产空调,则不符合开闭原则

优点
在这里插入图片描述
缺点
在这里插入图片描述
抽象工厂模式适用场合
在这里插入图片描述
在这里插入图片描述

二、生成器模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
例如:
在这里插入图片描述
1.确定Director,成员为xxxBuilder(表示要用到的生成器的父类),方法有设置生成器,获取产品(getXXX),创建整个产品的方法(这个方法用来调用生成器的各个方法,最后生成一个完整的产品)
2.确定XXXBuilder,成员为产品,方法就是构建这个产品所有部件所需的方法,以及getXXX获取产品,以及初始化产品的方法(肯定要先new申明一个空的产品,赋值给成员变量里的产品)
3.确定具体的生成器类,继承自XXXBuilder
4.确定具体产品,成员和方法就是该产品所需的各种方法属性等
例如:
在这里插入图片描述
优点:
在这里插入图片描述
缺点:
在这里插入图片描述
适用场合:
在这里插入图片描述
生成器模式与抽象工厂模式
在这里插入图片描述

三、单例模式

单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供一个全局访问点。
要点:

  1. 某个类只能有一个实例
  2. 它必须自行创建这个实例
  3. 它必须自行向整个系统提供这个实例

基本思路
在这里插入图片描述在这里插入图片描述
步骤如上

例如在这里插入图片描述在这里插入图片描述

多线程中的单例模式,在getInstance()方法应声明为synchronized,防止当唯一实例尚未创建时有两个线程同时调用创建方法,那么将导致两个现成各自创建了一个实例,从而违反了单例模式的实例唯一性的初衷

优点:

  1. 提供了对唯一的实例的受控访问
  2. 可以节约系统资源
  3. 允许可变数目的实例

缺点

  1. 单例类的扩展有很大的困难
  2. 单例类的职责过重
  3. 滥用单例将带来一些负面影响

适用环境
在这里插入图片描述

结构性软件设计模式

结构型软件设计模式的主要目的是将不同的类和对象组合在一起,形成更大或者更复杂的结构体。
在这里插入图片描述

一、组合模式

组合模式:组合多个对象形成树形结构表示“整体-部分”的结构层次。组合模式对单个对象(即叶子对象)组合对象(即容器对象)使用具有一致性

组合模式又可以称为“整体-部分”模式

组合模式结构

  • Component:为组合模式中的对象声明接口
  • Leaf:在组合模式中表示叶结点对象
  • Composite:表示组合部件
  • Client:通过Component接口操纵组合部件的对象
    在这里插入图片描述
    例子建议看书P56

关于组合模式的讨论
1.安全形式的组合模式
在这里插入图片描述
2.透明形式的组合模式
在这里插入图片描述
优点:
在这里插入图片描述
缺点:
在这里插入图片描述
适用环境
在这里插入图片描述

二、适配器模式

  • 适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用
  • 当客户类调用适配器的方法时,在适配器类的内部奖调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类
  • 适配器可以使由于接口不兼容而不能交互的类可以一起工作

模式可分为两种

  • 类适配器模式在这里插入图片描述

  • 对象适配器模式在这里插入图片描述
    例如:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    适配器的作用
    适配器模式是将接口不同而功能相近的两个接口加以转换,包括适配器角色补充一些源角色没有但目标接口需要的方法。

适配器模式可以用于增加新的方法,但主要意图是转换接口

类适配器模式与对象适配器模式的区别(本质上没什么区别,只是在实现上的区别,比如Java不能多继承,所以用对象适配器模式)
在这里插入图片描述
优点:
在这里插入图片描述
类适配器的优点
在这里插入图片描述

类适配器的缺点:

在这里插入图片描述
对象适配器的优点
在这里插入图片描述
对象适配器的缺点
在这里插入图片描述
适用场合
在这里插入图片描述

适配者模式的扩展
1.默认适配器模式(缺省适配器模式、单接口适配器模式)
在这里插入图片描述
在这里插入图片描述
2.双向适配器
在这里插入图片描述在这里插入图片描述

三、外观模式

  • 外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子接口更加容易使用
  • 外观模式又称为门面模式,它是一种对象结构型模式
    在这里插入图片描述

外观模式由三个角色组成:

  1. 外观角色外观模式的核心。它被客户角色调用,因此它熟悉子系统的功能。其内部根据客户橘色已有的需求预定了几种功能组合
  2. 子系统角色:实现子系统的功能,对它而言,外观角色就和客户角色一样是未知的,它没有任何外观角色的信息和链接
  3. 客户角色:调用外观角色来完成要得到的功能

外观模式讨论
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用外观模式的目的

  • 为一系列复杂的接口提供一个统一的接口,使该系统更容易使用

适配器模式与外观模式的区别

  • 适配器模式转换接口的目的是将一个不适用的接口转换为可以被使用的接口,或将一些接口不同而功能相近的接口加以转换,以便可以被统一使用
  • 外观模式简化接口的目的是为了更好地使用某个类库

四、桥接模式

  • 桥接模式将继承关系转换为关联关系,从而降低类与类之间的耦合,减少了代码编写量
  • 桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化
  • 它是一种对象结构型模式,又称为柄体模式或接口模式

例如:
在这里插入图片描述
在这里插入图片描述

1.确定抽象部分和实现部分
2.确定抽象部分的实现类,实现部分的实现类

优点
在这里插入图片描述
缺点
在这里插入图片描述
适用环境
在这里插入图片描述
适配器模式与桥接模式的联用
在这里插入图片描述在这里插入图片描述

行为型软件设计模式

概述
动机

  • 行为型软件设计模式关心算法和对象之间的责任分配,不仅是描述对象或类模式,更加侧重描述它们之间的通信模式

内容

  • 迭代器模式抽象了访问和遍历一个集合中的对象的方式
  • 访问者模式封装了分布于多个类之间的行为
  • 中介者模式通过在对象间引入一个中介对象,避免对象间的显式引用
  • 策略模式将算法封装在对象中,这样可以方便指定或改变一个对象使用的算法
  • 状态模式封装了兑现过的状态,使得当对象的状态发生变化时,该对象可以改变自身的行为

一、迭代器模式

在这里插入图片描述
迭代器模式的关键思想是将对列表的访问和遍历从列表对象中分离出来,放入一个独立的迭代对象中
在这里插入图片描述
迭代器里的四个方法(一般)
1.boolean hasNext()
2.next()
3.remove()
4.getNumOfItems()

在这里插入图片描述
在这里插入图片描述
优点
在这里插入图片描述
缺点
在这里插入图片描述
适用环境
在这里插入图片描述
模式应用
JDK1.2引入了新的Java聚合框架Collections
在这里插入图片描述

二、访问者模式

  • 对于系统中的某些对象,它们存储在同一个集合中,具有不同的类型
  • 对于该集合中的对象,可以接受一类被称为访问者的对象来访问
  • 不同的访问者其访问方式有所不同
  • 目的:封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变
  • 模式动机:为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式

在这里插入图片描述
在这里插入图片描述
访问者模式:表示一个作用于某对象结构中的个元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作
访问者模式是一种对象行为型模式
在这里插入图片描述

首先分为两个部分,一是元素类,而是访问者类
先抽象再具体
在访问者类里要有访问元素的方法visitXXX(抽象元素父类做参数)之类的
在元素类里要有接受访问的方法,比如accept(抽象访问者父类做参数)等

在这里插入图片描述
访问者与被访问者的关联
在这里插入图片描述
优点
在这里插入图片描述
缺点
在这里插入图片描述
适用场合
在这里插入图片描述
模式扩展
在这里插入图片描述

三、中介者模式

  • 模式动机:为了减少对象两之间复杂的引用关系,使之成为一个松耦合的系统,需要适用中介者模式
  • 定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使耦合松散,而且可以独立地该变它们之间的交互
  • 中介者模式又称为调停者模式,它是一种对象行为型模式
  • 中介者模式的要点是将所有对象之间的交互细节抽象到一个独立的类中,这个类叫做中介者类Mediator

简单来说就是增加一个第三者,控制中心之类的东西
在这里插入图片描述
中介者模式组成:

  1. Mediator:中介者接口
  2. ConcreteMediator:具体的中介者,可以有多个具体的中介者
  3. Colleague:参与者类接口
  4. ConcreteColleague:具体的参与者
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    优点
    在这里插入图片描述
    缺点
    在这里插入图片描述
    适用环境
    在这里插入图片描述
    模式应用
    在这里插入图片描述
    在这里插入图片描述

四、策略模式

简单说就是将算法作为一个类存在,而不是作为方法存在某个类之中
在这里插入图片描述
在这里插入图片描述

  • 定义:策略模式定义了一系列算法,将每一个算法封装起来,并且使它们之间可以相互替换。策略模式让算法的变化不会影响到适用算法的客户
  • 策略模式试对算法的封装,它把算法的责任和算法本身分隔开,委派给不同的对象管理

策略模式组成

  1. Strategy:定义了一个共同的接口,所有具体的算法类实现这个接口。环境(上下文)类Context使用这个接口调用具体的算法类
  2. ConcreteStrategy:封装了具体的算法,实现同一个接口
  3. Context:环境(上下文)类。用于配置一个具体的算法策略对象,维持一个策略接口类型的参考(Reference),并且可以定义一些让接口Strategy的具体对象访问的接口。在简单情况下,Context类可以省略。
    在这里插入图片描述
    在这里插入图片描述
    例如:
    在这里插入图片描述在这里插入图片描述
    模式应用
    在这里插入图片描述
    在这里插入图片描述
    策略模式与状态模式
    在这里插入图片描述
    适用环境
    在这里插入图片描述

优点
在这里插入图片描述

缺点
在这里插入图片描述

五、状态模式

与策略模式类似,状态模式将不同状态下的行为封装在不同的类中,每个类代表一个状态
状态模式的组成

  1. Context:定义了与客户程序的接口,它保持了一个concreteState的代表现在状态的实例
  2. State:定义了状态接口,它的各个子类封装了在各种不同状态下的行为
  3. ConcreteState子类:封装了在各种不同状态下的行为
    在这里插入图片描述在这里插入图片描述
  • 状态模式描述了对象状态的变化以及对象如何在每一种状态下表现除不同的行为
  • 状态模式的关键是引入了一个抽象类来专门表示对象的状态,这个类我们叫做抽象状态类,而对象的每一种具体状态类都继承了该类,并在不同具体状态类中实现了不同状态的行为,包括各种状态之间的切换

策略模式和状态模式的相似之处
在这里插入图片描述
策略模式和状态模式的区别
在这里插入图片描述
优点
在这里插入图片描述

  • 9
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值