6中结构型设计模式的对比理解(Composite组合模式,Proxy代理模式,Flyweight享元模式,Facade门面模式,Bridge桥接模式,Decorator装饰器模式)

结构型模式

结构型模式用来组装 类和对象,以获得更大的结构。

结构型类模式,通过继承机制来组合接口或类。简单的例子就是多重继承,最后一个类拥有所有父类的性质。这个模式有助于独立开发一个协同类。另一个例子是类型是的 Adapter 模式,它通过私有继承待适配接口(C++),生成一个多接口的抽象,这个抽象就可以被当做待适配接口的占位符。

结构型对象模式不是对接口和类进行组合,而是对对象进行组合。从而可以动态改变组合,得出新功能。因此更加灵活。结构型对象模式常见有如下几种:

  1. Composite模式。构造一个类层次结构,这个层次结构中有两种类,一种是基元类,一种是组合类。其中组合类可以组合基元类和组合类,从而可以构造出很复杂结构。
  2. Proxy模式。Proxy对象用作其他对象的占位符,因此可以对被代理对象的请求做一些额外的操作,比如安全检查。同时也可以增减,限制,修改被代理对象提供的功能。
  3. Flyweight模式。创建可以共享的没有状态的对象。
  4. Facade模式。创建单个对象,以表示整个系统。(这个对象会将请求转发给所表示的对象)
  5. Bridge模式。该模式分离对象的抽象和实现,这样两边都可以演化。
  6. Decorator模式。该模式用于动态给对象增加功能。

这部分我们使用跟创建型模式一样的例子。即一个迷宫游戏。这个游戏的组件有:

  • Maze – 迷宫,由多个房间组成
  • Room – 房间,有 东南西北 四个方向,每个方向要么是墙壁,要么是门
  • Door – 门,组成房间
  • Wall – 墙壁,组成房间

这些是抽象类,迷宫有两种实现,一种是正常的迷宫,即门使用钥匙打开,墙壁是水泥墙壁。另一种是魔法迷宫,门是魔法门,使用咒语打开,墙壁是魔法墙壁。

1. Adapter

Adapter 模式是使用一个已有的类或对象来实现我们的接口。

比如上面的例子,假设正常迷宫的组件已经实现好了,现在要实现魔法迷宫。需要实现一个魔法墙,这个墙壁可以使用法杖打开。我们知道正常迷宫的门是可以使用钥匙打开的。所以我们不想再实现,想要套用正常迷宫的门对象,然后给它传递一个特殊的钥匙(法杖)就来打开墙壁(切换到另一个房间)。

这时候合适使用 Adapter 模式,即使用【正常门】实现【魔法墙】。其中【正常门】称为 Adaptee,【魔法墙】称为 Adapter。

Adapter 有两种形式,一种使用继承(基于类),另一种使用组合(基于对象)。他们的结构分别如下所示:

  1. Adapter类模式结构(使用继承)

在这里插入图片描述

  1. Adapter 对象模式(使用组合)

在这里插入图片描述

2. Bridge

Bridge 用来分离抽象和实现。

举个例子:用上面的例子,我们的迷宫游戏中有墙,墙的实现有两种 一般墙 和 魔法墙。假如现在我们还要求有的需要显示一些文字来作为迷宫的线索。那么就会多出两中墙,空白墙 和 文字墙。

如果我们使用原先抽象和实现来实现,我们需要实现四个类,NormalBlankWall,NormalTextWall,MagicBlankWall,MagicTextWall ,我们的结构图如下所示:

在这里插入图片描述

但是,如果使用 Bridge 模式,我们可以将 Wall 的抽象 和 实现分开,这样抽象和实现可单独演化。使用 Bridge 模式的结构图如下所示:

在这里插入图片描述

上面的 Wall 和 WallImplementor 的关系称为桥接。(其实就是一个引用)

3.Composite模式

Composite模式用来构建树形结构。以使应用以同样的方式对待 叶子节点 和 非叶子节点。

还用迷宫游戏做例子,假设现在我们的迷宫组件可以爆炸,它们的 Door/Wall/Room 可以通过特定的方式炸掉。被 Wall/Door 被炸掉后,就可以进入到对面房间。Room被炸掉后,就可以进入四个方向的任意房间。这时候,就可以使用 Composite 模式了。

首先,我们需要构造一个抽象的 BombComponent。这个接口声明一个 bomb 方法。BombDoor / BombWall / BombRoom 通过实现这个 bomb 方法来完成爆炸。但是这个 BombComponent 除了声明 bomb 方法。它还声明了 add, remove,getChild 方法。后面这三个方法就是 BombComponent 之所以称为 Composite 模式的原因。

BombDoor / BombWall 分别实现 BombComponent 的 bomb 方法来销毁它们即可。但是 BombRoom 需要除了需要在 bomb 方法中销毁自己以外,它还需要销毁四个方向的 BombDoor, BombWall 等子组件。下面是它们的结构图:

在这里插入图片描述

上面的 BombWall 和 BombDoor 是叶子节点,add, remove, getChild 方法只需要一个默认什么也不做的实现即可。但是 BombRoom 是组合节点。需要实现这些方法。并使用一个实例变量 list 来存储它的子组件。(子组件既可以是叶子节点,也可以是组合节点)。我们说上面 BombRoom 实现了 Composite 模式。

4.Decorator

Decorator模式用来动态增加对象的功能。相比继承来增加功能, Decorator更加灵活一些。

上面使用 Bridge 模式来新增一个带有文本的墙壁。这是新增了一类墙壁。可以使用文本墙,也可以使用普通墙。但是如果我们仅仅想对某一些构建好的普通墙壁动态涂上文本,对另一些构建好的墙壁涂上图片等。这个时候可以使用 Decorator 模式。这样在需要显示文字的时候,给它装饰 Decorator 就可以了。

Decorator模式的结构图如下所示:

在这里插入图片描述

这里需要注意的是,Decorator类需要一个实现 Wall 接口的同时,持有一个 Wall 接口实例(这个实例可以是Decorator子类)。

Decorator 实现 Wall 接口是为了让 Decorator 和 Wall 实现类完全一样。Wall实现类能出现的地方,Decorator都能出现。

Decorator 持有 Wall 实例的原因是:使用这个 Wall 实例来实现 Wall 接口。然后 Decorator 子类在此基础上在扩展,就可以给持有的 Wall 实例增强功能了。

5.Facade

Facade模式用来给一个系统提供一个统一的接口。

我们的迷宫游戏不合适Facade模式,因为迷宫游戏不是一个系统,不向外提供接口。但是有很多系统很复杂,它们向外提供很多接口,通过这些接口来使用系统功能。调用不同的接口组合实现不同的功能。

有时候,系统提供的接口过于细节。很多实用系统的人都不需要全部的自定义能力。这时候,可以提供一个Facade类,这个类整合系统所有接口,向外提供一个默认功能。绝大部分人通过Facade使用系统就可以了。

这样普通开发人员使用Facade,需要对系统有特殊需求的人员也可以直接调用系统提供的接口。

Facade模式的结构如下所示:

在这里插入图片描述

如果使用系统的默认方式不止一种,也可以提供一个 Facade 抽象类,每个 Facade 子类,再提供具体使用系统流程。

6.Flyweight

享元模式。这个模式是用来共享对象的。

假如,迷宫游戏的迷宫很大。这样就会需要很多房间,每个房间至少2面墙壁/门。这样当房间的数量很多的时候,应用就需要实例化大量的门/墙对象。因此我们可以使用享元模式来实现它们。前后的结构变化示意图如下:

在这里插入图片描述

这样,整个应用的墙/门,就都只有两个实例了。然后门/墙的状态信息保存在房间中。比如有的前是文字墙,有的墙是图片墙。当房间在构建时,它传递这个状态给墙/门,然后墙/门再根据状态生成它们自己。

下面是 Flyweight 模式的结构示意图:

在这里插入图片描述

从上图可以看到,Flyweight 除了有共享的对象,还有不共享的对象。注意 Flyweight 接口中应该还维持一个状态,通过这个状态配置每个共享对象。

7.Proxy

Proxy 模式是用来给一些对象做占位符的。常用的被占位的对象有如下3中:

  1. 大对象 – 加载需要很长时间,使用代理模式先占位,真正需要用到目标对象再加载。这种代理模式叫 虚代理(virtual proxy)
  2. 远程对象 – 在不同进程空间的对象,通过代理操作远程对象。这种代理模式叫 远程代理(remote proxy)
  3. 重要对象 – 需要进行安全保护的对象,限制对目标对象的某些操作。这种代理模式叫 保护代理(protection proxy)

总之,Proxy 模式用来占位,然后在合适的时候将请求发送到真正对象。

这里通过上面迷宫游戏,举例一个 虚代理。

之前我们使用 Decorator 来给 Wall 画上图片。现在我们当这种 Decorator Wall 是一种 Wall 实现,叫 ImageWall。现在假设图片都在硬盘上,当迷宫很大,而且有很多的 ImageWall 时,若在玩家开始游戏时就构建整个迷宫的 ImageWall,那较长的时间去操作硬盘。这时候可以使用 Proxy 模式。ProxyWall 先用来占个位,把迷宫构建起来,当玩家真正进入到房间需要一个 ImageWall 的时候,ProxyWall 再从磁盘中读取图片,构建ImageWall,之后所有对 ProxyWall 的操作,都转到新建的 ImageWall 上。

下图是 Proxy 模式的结构图:

在这里插入图片描述

这个模式比较简单,但是要注意如下两点:

  1. 它跟 Adapter 模式差异:Adapter 模式是适配两个接口,这里没有适配其他接口
  2. 它跟 Decorator 模式差异:Decorator 模式是为了增加功能,但是这里没有增加功能。其次 Decorator 模式一直持有被装饰对象,但是 Proxy 模式不一定持有(远程代理)。最后,不像 Decorator,Proxy 没有递归引用(其实有时也有,这样 Proxy 就引用一个抽象接口。但虚代理最后要实例化被代理类,所以虚代理需要知道这个最终类)。

8.结构型模式汇总

结构型模式是为了构建大对象。结构型模式分为类模式 和 对象模式,类模式是静态的 而 对象模式是动态的,因此对象模式更加灵活。下面复制第一部分内容用于回顾:

结构型类模式,通过继承机制来组合接口或类。简单的例子就是多重继承,最后一个类拥有所有父类的性质。这个模式有助于独立开发一个协同类。另一个例子是类型是的 Adapter 模式,它通过私有继承待适配接口(C++),生成一个多接口的抽象,这个抽象就可以被当做待适配接口的占位符。

结构型对象模式不是对接口和类进行组合,而是对对象进行组合。从而可以动态改变组合,得出新功能。因此更加灵活。结构型对象模式常见有如下几种:

  1. Composite模式。构造一个类层次结构,这个层次结构中有两种类,一种是基元类,一种是组合类。其中组合类可以组合基元类和组合类,从而可以构造出很复杂结构。
  2. Proxy模式。Proxy对象用作其他对象的占位符,因此可以对被代理对象的请求做一些额外的操作,比如安全检查。同时也可以增减,限制,修改被代理对象提供的功能。
  3. Flyweight模式。创建可以共享的没有状态的对象。
  4. Facade模式。创建单个对象,以表示整个系统。(这个对象会将请求转发给所表示的对象)
  5. Bridge模式。该模式分离对象的抽象和实现,这样两边都可以演化。
  6. Decorator模式。该模式用于动态给对象增加功能。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值