现在在大力推行节约型社会,“浪费可耻,节俭光荣”。在软件系统中,有时候也会存在资源浪费的情况,例如,在计算机内存中存储了多个完全相同或者非常相似的对象,如果这些对象的数量太多将导致系统运行代价过高。那么,是否存在一种技术可以用于节约内存使用空间,实现对这些相同或者相似对象的共享访问呢?答案是肯定的,这种技术就是享元模式。

享元模式(Flyweight) 学习难度:★★★★☆ 使用频率:★☆☆☆☆

一、围棋棋子的设计

M公司开发部欲开发一个围棋软件,其界面效果如下图所示:

  M公司开发人员通过对围棋软件进行分析,发现在围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。如果将每一个棋子都作为一个独立的对象存储在内存中,将可能导致该围棋软件在运行时所需要的内存空间较大。

  如何降低运行代价、提高系统性能是M公司开发人员需要解决的一个问题。为此,M公司开发人员决定使用享元模式来设计该软件。

二、享元模式概述

2.1 享元模式简介

享元(Flyweight)模式:运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,是一种结构型模式。

2.2 享元模式结构

  享元模式的结构较为复杂,一般结合工厂模式一起使用,在其结构图中包含了一个享元工厂类,如下图所示:

  由上图可以看出,它包含了以下4个角色:

  (1)Flyweight(抽象享元类):一个接口或抽象类,声明了具体享元类的公共方法。

  (2)ConcreteFlyweight(具体享元类):实现了抽象享元类,其实例称为享元对象。

  (3)UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为费共享具体享元类。

  (4)FlyweightFactory(享元工厂类):用于创建并管理享元对象,一般设计为一个存储“Key-Value”键值对的集合(可以结合工厂模式设计)。其作用就在于:提供一个用于存储享元对象的享元池,当用户需要对象时,首先从享元池中获取,如果享元池中不存在,那么则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。=> 想想.NET中的各种资源池的设计?

三、重构后的围棋棋子方案

3.1 重构后的设计

  M公司开发人员采用了享元模式进行设计,如下图所示:

  其中,IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman充当具体享元类,IgoChessmanFactory充当享元工厂类。

3.2 具体代码实现

  (1)抽象享元类:IgoChessman

    public abstract class IgoChessman{public abstract string GetColor();public void Display(Coordinates coord){Console.WriteLine("棋子颜色:{0},棋子位置:{1}", GetColor(), coord.X + "," + coord.Y);}}/// <summary>/// 外部状态:棋子坐标/// </summary>public class Coordinates{public int X { get; set; }public int Y { get; set; }public Coordinates(){}public Coordinates(int x, int y){this.X = x;this.Y = y;}}

  (2)具体享元类:BlackIgoChessman、WhiteIgoChessman

    // 具体享元类Apublic class BlackIgoChessman : IgoChessman{public override string GetColor(){return "黑色";}}// 具体享元类Bpublic class WhiteIgoChessman : IgoChessman{public override string GetColor(){return "白色";}}

  (3)享元工厂类:IgoChessmanFactory

    /// <summary>/// 享元工厂类/// </summary>public class IgoChessmanFactory{private static readonly IgoChessmanFactory instance = new IgoChessmanFactory(); // 使用单例模式实现享元private static Hashtable ht;    // 使用Hashtable来存储享元对象,充当享元池private IgoChessmanFactory(){ht = new Hashtable();IgoChessman blackChess = new BlackIgoChessman();ht.Add("b", blackChess);IgoChessman whiteChess = new WhiteIgoChessman();ht.Add("w", whiteChess);}public static IgoChessmanFactory GetInstance(){return instance;}public IgoChessman GetIgoChessman(string color){IgoChessman chess = ht[color] as IgoChessman;return chess;}}

  (4)客户端调用

    public class Program{public static void Main(string[] args){// 获取享元工厂IgoChessmanFactory chessFactory = IgoChessmanFactory.GetInstance();// 通过享元工厂获取3颗黑子IgoChessman blackChess1 = chessFactory.GetIgoChessman("b");IgoChessman blackChess2 = chessFactory.GetIgoChessman("b");IgoChessman blackChess3 = chessFactory.GetIgoChessman("b");Console.WriteLine("判断两颗黑子是否相同:{0}", object.ReferenceEquals(blackChess1, blackChess2));// 通过享元工厂获取2颗白子IgoChessman whiteChess1 = chessFactory.GetIgoChessman("w");IgoChessman whiteChess2 = chessFactory.GetIgoChessman("w");Console.WriteLine("判断两颗白子是否相同:{0}", object.ReferenceEquals(whiteChess1, whiteChess2));// 显示棋子blackChess1.Display(new Coordinates(1,2));blackChess2.Display(new Coordinates(3, 4));blackChess3.Display(new Coordinates(1, 3));whiteChess1.Display(new Coordinates(2, 5));whiteChess2.Display(new Coordinates(2, 4));Console.ReadKey();}}

  运行结果如下图所示:

  

  从运行结果可以看出,在每次调用Display()方法时,都设置了不同的外部状态-坐标值,因此相同的棋子虽然具有相同的颜色,但是它们的坐标值不同,将显示在棋盘的不同位置。

四、享元模式总结

4.1 主要优点

  可以极大减少内存中对象的数量,使得相同或相似对象在内存中只有一份 => 节省系统资源,提高系统性能!棒棒哒!

4.2 主要缺点

  为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长!

4.3 应用场景

  (1)一个系统有大量相同或相似的对象,造成了系统内存的大量损耗 => 赶紧使用享元模式吧!

  (2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

  (3)要维护享元模式,需要耗费一定的系统资源,因为在需要时会多次重复使用才值得使用享元模式了!

参考资料

  

  刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

转载于:https://www.cnblogs.com/edisonchou/p/7148258.html

设计模式的征途—12.享元(Flyweight)模式相关推荐

  1. 设计模式(11)——享元(Flyweight)模式

    什么是享元模式? 享元模式跟CACHE机制类似,它运用共享技术有效地支持大量细粒度的对象.Flyweight通过尽可能地与其他对象共享数据来减少对内存的使用. Flyweight的经典例子就是字符处理 ...

  2. 设计模式学习笔记——享元(Flyweight)模式

    设计模式学习笔记--享元(Flyweight)模式 @(设计模式)[设计模式, 享元模式, flyweight] 设计模式学习笔记享元Flyweight模式 基本介绍 享元案例 类图 实现代码 Big ...

  3. Java 实现享元(Flyweight)模式

    /*** 字母* @author stone**/ public class Letter {private String name;public Letter(String name) {this. ...

  4. 设计模式学习笔记--享元(Flyweight)模式

    写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式 ...

  5. python 享元模式_python 设计模式之享元(Flyweight)模式

    #写在前面 这个设计模式理解起来很容易.百度百科上说的有点绕口. #享元模式的定义 运用共享技术来有効地支持大量细粒度对象的复用. 它通过共享已经存在的对橡大幅度减少需要创建的对象数量.避免大量相似类 ...

  6. 设计模式--享元(Flyweight)模式

    模式定义 运用共享技术有效地支持大量细粒度的对象 类图 应用场景 如果系统有大量类似的对象,可以使用享元模式 优点 如果系统有大量类似的对象,可以节省大量的内存及CPU资源 要点总结 要点总结 如果系 ...

  7. java 地图模式_Java设计模式之从[Dota地图]分析享元(Flyweight)模式

    在Dota游戏的地图中有几百棵树,现在假设这些树木无非是这两种:白杨.枫树,数量一共为400棵,那么,在装载这个地图场景的时候,我们是不是应该给这400课树一一建立对象呢?(如:MapItem tre ...

  8. Java设计模式之享元flyweight模式代码示例

  9. 设计模式(十)享元模式Flyweight(结构型)

    设计模式(十)享元模式Flyweight(结构型) 说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释 ...

最新文章

  1. 计算机语言 angela,Angela
  2. 用c#编写爬虫在marinetraffic下载船仅仅图片
  3. linux命令详解——sar
  4. 学习OpenGL ES之法线贴图
  5. Kubernetes学习笔记 黑马程序员
  6. 安装FlexPro和设置FlexPro许可证管理器
  7. 这个游戏引擎开源了!
  8. Java工作流有哪些?如何快速掌握Java技术
  9. MStar点屏(LVDS接口屏)
  10. 我的系統中存在的问题
  11. 用计算机公式表白,昨天,我用IF函数表白成功了!
  12. 保险行业的电子签章应用场景:印章统一管、合同在线签
  13. 天津市科技领军企业和领军培育企业补助奖励及认定条件,补贴500万
  14. 员工转正申请书_简短的员工转正申请书范文6篇
  15. Mq的幂等性问题分析和基本处理
  16. unity2d游戏开发系列教程:四、一个2D游戏所需要的主要功能(游戏框架)
  17. ServiceMesh实践与探索
  18. CRC16冗余循环检测计算器-好用。modbus RTU
  19. 2023年第三届纳米材料与纳米技术国际会议(NanoMT 2023)
  20. STM32 RTC时钟掉电日期不更新 STM32 HAL库RTC时钟配置

热门文章

  1. c++中宏定义的妙用
  2. C++Builder中使用Pas文件
  3. bash脚本一条命令直接发送http请求
  4. 在pycharm安装MySQLdb库和pymysql库的区别
  5. java 操作 ES 的方式 整理总结
  6. 内核中的kmalloc函数详解
  7. zcmu1716(思维)
  8. oracle 分析视图,ORACLE 性能视图的分析和使用
  9. Android截屏方法总结
  10. Creating a Java VM from Android Native Code