设计模式之享元模式详解

概述

享元模式定义:

运用共享技术来有效地支持大量细粒度对象的复用。它==通过共享已经存在的对象来大幅度减少需要创建的对象数量==、避免大量相似对象的开销,从而提高系统资源的利用率。

结构

享元(Flyweight )模式中存在以下两种状态:

享元模式以共享的方式高效地支持大量细粒度对象的重用,能做到共享的关键就是区分了内部状态(Intrinsic State)和外部状态(Extrinsic State)。

  1. 内部状态,即不会随着环境的改变而改变的可共享部分。
  2. 外部状态,指随环境改变而改变的不可以共享的部分。(可以使用参数形式进行传递)享元对象的外部状态通常由客户端保存,并在享元对象被创建之后,需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态之间是相互独立的。

享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。

正因为区分了内部状态和外部状态,我们可以将具有相同内部状态的对象存储在享元池中,享元池中的对象是可以实现共享的,需要的时候就将对象从享元池中取出,实现对象的复用。通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份。

享元模式结构较为复杂,一般结合工厂模式一起使用。主要有以下角色:

  • 抽象享元角色(Flyweight):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。
  • 具体享元(Concrete Flyweight)角色 :它实现了抽象享元类,称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象
  • 非享元(Unsharable Flyweight)角色 :并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
  • 享元工厂(Flyweight Factory)角色 :负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

在享元模式中引入了享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

案例实现

【例】俄罗斯方块

下面的图片是众所周知的俄罗斯方块中的一个个方块,这些方块有形状相同但颜色不一样的,如果在俄罗斯方块这个游戏中,每个不同或形状相同但颜色不一样的的方块都是一个实例对象,这些对象就要占用很多的内存空间,我们利用享元模式进行实现,将相同形状不同颜色的颜色看成是可变的外部状态。

先来看类图:

代码如下:

享元类的设计是享元模式的要点之一,在享元类中要将内部状态和外部状态分开处理,通常将内部状态作为享元类的成员变量,而外部状态通过注入或形参的方式添加到享元类中。

俄罗斯方块有不同的形状,我们可以对这些形状向上抽取出AbstractBox抽象享元角色,用来定义共性的属性和行为。

public abstract class AbstractBox {//获取图形public abstract String getShape();//显示图形及颜色,颜色在调用该方法时由外部参数传递public void display(String color) {System.out.println("方块形状:" + this.getShape() + " 颜色:" + color);}
}

接下来就是定义不同的形状了,IBox类、LBox类、OBox类等,属于具体享元角色(根据情况可以使用单例模式)。

public class IBox extends AbstractBox {@Overridepublic String getShape() {return "I";}
}public class LBox extends AbstractBox {@Overridepublic String getShape() {return "L";}
}public class OBox extends AbstractBox {@Overridepublic String getShape() {return "O";}
}

提供了一个工厂类(BoxFactory),用来管理享元对象(也就是AbstractBox子类对象),该工厂类对象只需要一个,所以可以使用单例模式。并给工厂类提供一个获取形状的方法。

public class BoxFactory {//这个map是用来存储已经创建的具体图形对象,当你需要具体形状时可以从该对象中获取private static HashMap<String, AbstractBox> map;private BoxFactory() {map = new HashMap<String, AbstractBox>();AbstractBox iBox = new IBox();AbstractBox lBox = new LBox();AbstractBox oBox = new OBox();map.put("I", iBox);map.put("L", lBox);map.put("O", oBox);}public static final BoxFactory getInstance() {return SingletonHolder.INSTANCE;}private static class SingletonHolder {private static final BoxFactory INSTANCE = new BoxFactory();}//根据图像名称获取对象public AbstractBox getBox(String key) {return map.get(key);}
}

享元模式补充

与其他模式使用

享元模式通常需要和其他模式一起联用,几种常见的联用方式如下:

(1)在享元模式的享元工厂类中通常提供一个静态的工厂方法用于返回享元对象,使用简单工厂模式来生成享元对象。

(2)在一个系统中,通常只有唯一一个享元工厂,因此可以使用单例模式进行享元工厂类的设计。

(3)享元模式可以结合组合模式形成复合享元模式,统一对多个享元对象设置外部状态。

单纯享元模式和复合享元模式

单纯享元模式

在单纯享元模式中,所有的具体享元类都是可以共享的,不存在非共享具体享元类。

复合享元模式

将一些单纯享元对象使用组合模式加以组合,还可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。
通过复合享元模式,可以确保复合享元类中所包含的每个单纯享元类都具有相同的外部状态,而这些单纯享元的内部状态往往可以不同。如果希望为多个内部状态不同的享元对象设置相同的外部状态,可以考虑使用复合享元模式。

优缺点和使用场景

当系统中存在大量相同或者相似的对象时,享元模式是一种较好的解决方案,它通过共享技术实现相同或相似的细粒度对象的复用,从而节约了内存空间,提高了系统性能。相比其他结构型设计模式,享元模式的使用频率并不算太高,但是作为一种以“节约内存,提高性能”为出发点的设计模式,它在软件开发中还是得到了一定程度的应用。

1,优点

  • 极大减少内存中相似或相同对象数量,节约系统资源,提供系统性能
  • 享元模式中的外部状态相对独立,且不影响内部状态

2,缺点:

为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,使程序逻辑复杂

3,使用场景:

  • 一个系统有大量相同或者相似的对象,造成内存的大量耗费。
  • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
  • 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,应当在需要多次重复使用享元对象时才值得使用享元模式。(比如说一开始就将享元模式中的对象添加进内存用的次数却寥寥无几,这样享元模式也就失去了意义)

设计模式之享元模式详解相关推荐

  1. 设计模式之- 享元模式详解(都市异能版)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 魔都. 自从越狱风波过去以后 ...

  2. (十八)享元模式详解(都市异能版) - 转

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. 魔都. 自从越狱风波过去以后,小左的生活便又回到了之前的节奏,依旧是每日徘徊在魔都某天桥,继续着自己的算命之旅. 说起这次越狱风波,着 ...

  3. (十八)享元模式详解(都市异能版)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. 魔都. 自从越狱风波过去以后,小左的生活便又回到了之前的节奏,依旧是每日徘徊在魔都某天桥,继续着自己的算命之旅. 说起这次越狱风波,着 ...

  4. Java设计模式之享元模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  5. 详解设计模式:享元模式

    享元模式(Flyweight Pattern),是对象池的一种体现,也是 GoF 的 23 种设计模式中的一种结构型设计模式. 享元模式 主要用于减少创建对象的数量,以减少内存占用和提高性能.它提供了 ...

  6. 走穿java23种设计模式-15责任链模式详解

    走穿java23种设计模式-15责任链模式详解 责任链模式是一种常见的行为模式. 一.责任链模式的现实场景 习伟过生日邀请了很多朋友到KTV一起庆祝,为了增加欢乐的气氛,习伟建议大家一起玩击鼓传花的游 ...

  7. 走穿java23种设计模式--18中介者模式详解

    走穿java23种设计模式–18中介者模式详解 中介者模式也称调停者模式,是一种比较简单的模式. 一.中介者模式的现实场景 蔡良因为上次表白时对方只看重他的物质方面,所以他对女朋友这个问题有点失望.因 ...

  8. 北风设计模式课程---享元模式

    北风设计模式课程---享元模式 一.总结 一句话总结: 不仅要通过视频学,还要看别的博客里面的介绍,搜讲解,搜作用,搜实例 1.享元模式的本质是什么? 池技术:各种缓存池都是享元模式的体现 说到享元模 ...

  9. 每天一个设计模式之享元模式

    作者按:<每天一个设计模式>旨在初步领会设计模式的精髓,目前采用javascript和python两种语言实现.诚然,每种设计模式都有多种实现方式,但此小册只记录最直截了当的实现方式 :) ...

最新文章

  1. u8 采购到货单中的 业务类型 没有表字典,是系统预置 存入表也是文字: 普通采购 - 固定资产...
  2. 揭开互联网公司的神秘面纱,数据解读那些slay整个行业的互联网公司
  3. block里的self、weakSelf、strongSelf
  4. 笔记本启动关闭小键盘NUM LOCK的N种方法
  5. SystemVerilog中package(包)的基本使用
  6. RabbitMQ(7)-发后即忘模型
  7. 关于进行安装程序出现注册DLL/OCX失败,返回码:0x5问题
  8. 计算机毕业设计jsp酒店管理系统
  9. 计算机基础知识点总结
  10. 【51单片机实例教程】智能小车(一)让你的小车跑起来
  11. scrum敏捷开发方法论
  12. Windows密钥备份
  13. Alien Skin Exposure X4 Bundle 4.5.3.66 特别版 Mac 模拟胶片效果调色滤镜
  14. TMS320F280049 I2C IIC 相对于库函数操作CAT24C02 中文
  15. AIGC席卷,抖快、阅文、知乎大战网文圈
  16. SolidWorks2020绘制XT60PW-M模型
  17. C++类和对象的使用之对象指针
  18. laravel ckeditor上传图片
  19. 物联网设备数据流转之数据如何实时推送至前端:WebSocket服务端推送
  20. MD5及公私钥数据加密工具类

热门文章

  1. ISO14229-1专栏(5)--诊断与通信管理功能单元服务介绍
  2. Linux hostname命令详解
  3. 新买的四件套不洗可以用吗
  4. python合并excel出现多余列等问题
  5. [Python Gui]PySide6的Helloworld
  6. af dns 刷新时间_APP网络优化之DNS优化实践
  7. 易优cms传奇竞技游戏公司网站模板源码
  8. 用MySQL绘制新年祝福图形_2017微信拜年图片-2017微信拜年动态表情图片高清完整版-东坡下载...
  9. Heartbeat 下载和脚本安装
  10. 【JAVA秒会技术之玩转SQL】MySQL优化技术(一)