结构类模式(六):享元(Flyweight)
定义
运用共享技术有效的支持大量细粒度的对象。
两个状态
- 内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的。
- 外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。
和对象池的区别
- 对象池主要解决对象的复用问题,池中的每个对象都是可以替换的,从池中获取对象A和获取对象B对客户端而言都是一样的。
- 享元模式主要解决对象的共享问题,建立多个细粒度的可以进行共享的对象是其关注的重点。
UML

优点
- 减少运行时对象实例的个数,节省内存。
- 将许多“虚拟”对象的状态集中管理。
缺点
- 一旦你实现了它,单个的逻辑实现将无法拥有独立而不同的行为。
应用场景
- 系统中有大量对象且这些对象消耗大量内存。
- 这些对象的状态大部分可以外部化。
- 这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
示例
我们考虑一个场景,当我们需要自己实现绘制艺术字时,每一个字符都会有下面的几个状态:1.字体轮廓(这部分就是最耗内存的部分,每个字体都会有大量的数据来记录该字体的样式);2.字体字符(标志该字体用来表示哪一个字符);3.字体大小;4.字体位置。
当我们使用该艺术字来呈现一堆文本时,如果每个字符都加载同一份轮廓则会对内存和GC造成压力。
我们会发现对于同一个字符来说,轮廓和字符都是一致的内部状态,而大小和位置则是会变动的外部状态;我们通过使用享元模式来节省内存的使用;
Java
import java.util.HashMap;
import java.util.Map; public class Main
{
public static void main(String[] args)
{
String text = "Hello World! Hello Flyweight!";
for (int i = 0; i < text.length(); i++)
{
char c = text.charAt(i);
FontFlyweight font = (FontFlyweight) FontFlyweightFactory.getFont(c);
font.size = (int) ((Math.random() * 20) + 7);
font.x = (int) ((Math.random() * 500));
font.y = (int) ((Math.random() * 500));
font.drawFont();
}
FontFlyweightFactory.printFontCount();
} /**
* 字体享元接口
*/
public interface IFontFlyweight
{
/**
* 绘制当前字体
*/
void drawFont();
} /**
* 字体享元类
*/
public static class FontFlyweight implements IFontFlyweight
{
/**
* 不会改变可以共享的内部状态
*/
public final char symbol;
public final String font; /**
* 频繁改变不可以共享的外部状态
*/
public int size;
public int x;
public int y; public FontFlyweight(char symbol)
{
this.symbol = symbol;
//这里一般会从硬盘读取指定的美术字的字体样式
this.font = "自定义的美术字";
} @Override
public void drawFont()
{
//实际上绘制一个指定样式的矢量字符是非常复杂的,内存中需要保存该字符的所有矢量信息,会占用比较大的内存开销
System.out.println("在位置(" + x + ", " + y + ")处使用字体\"" + font + "\"绘制\"" + size + "\"号尺寸的字符\"" + symbol + "\"");
}
} /**
* 字体享元工厂
*/
public static class FontFlyweightFactory
{
private static Map<Character, IFontFlyweight> _map = new HashMap<>(); /**
* 根据外部状态获取对应的享元对象
*/
public static IFontFlyweight getFont(char key)
{
if(_map.containsKey(key))
{
return _map.get(key);
}
IFontFlyweight info = new FontFlyweight(key);
_map.put(key, info);
return info;
} public static void printFontCount()
{
System.out.println("内存中存在的字体实例数量:" + _map.values().size());
}
}
}
结构类模式(六):享元(Flyweight)的更多相关文章
- 结构型模式(六) 享元模式(Flyweight)
一.动机(Motivate) 在软件系统中,采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价--主要指内存需求方面的代价.如何在避免大量细粒度对象问题的同时,让外 ...
- 十一、结构模式之享元(Flyweight)模式
什么是享元模式 享元模式是对象的结构模式,是运用共享技术来有效的支持大量细粒度的对象.享元对象能做到共享的关键是区分内蕴状态和外蕴状态.一个内蕴状态是存储在享元对象内部,并且是不会随环境改变而有所不同 ...
- 十二、享元(Flyweight)模式--结构模式(Structural Pattern)
Flyweight在拳击比赛中指最轻量级,即"蝇量级",有些作者翻译为"羽量级".这里使用"享元 模式"更能反映模式的用意. 享元模式以共享 ...
- 七个结构模式之享元模式(Flyweight Pattern)
定义: 运用共享技术对大量细粒度对象的复用,这要求这些对象都很相似,状态变化很小.将这些对象的内部状态和外部状态进行区分,对于内部状态相同的只存储一个对象,而对不同的外部状态则采用不同的操作. 结构图 ...
- 享元(FlyWeight)模式
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式.享元模式尝试 ...
- Java 实现享元(Flyweight)模式
/** * 字母 * @author stone * */ public class Letter { private String name; public Letter(String name) ...
- 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)
结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题. 结构 ...
- 设计模式之结构类模式大PK
结构类模式大PK 结构类模式包括适配器模式.桥梁模式.组合模式.装饰模式.门面模式.享元模式和代理模式.之所以称其为结构类模式,是因 ...
- 设计模式之结构类模式PK
结构类模式包括: 适配器模式 桥梁模式 组合模式 装饰模式 门面模式 享元模式 代理模式 结构类模式着重于如何建立一个软件结构 为什么叫结构类模式呢? 因为他们都是通过组合类或对象产生更大结构以适应更 ...
随机推荐
- pandas
- android中handler用法总结
一.Handler的定义: Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中 ...
- LeetCode——Add Two Numbers
Question:You are given two linked lists representing two non-negative numbers. The digits are stored ...
- centos下安装xfce+vnc
首先安装桌面环境,我选择的是xfce,轻量级桌面,小巧实用不占太多内存,(占用内存方面,xfce少于kde,kde少于gnome). 安装xfce桌面一开始我以为第三方的软件源如rpmforge等应该 ...
- 【转】使用Xcode和Instruments调试解决iOS内存泄露
原文网址:http://blog.csdn.net/totogo2010/article/details/8233565 虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄 ...
- C#实现CAD数据转shape或mdb
jojojojo2002 原文C#实现CAD数据转shape或mdb 本文所指的CAD数据为不带空间参考和扩展数据的数据.如果CAD带了空间参考或是扩展属性数据的话,就要采用图形和属性分离的方法转CA ...
- Effective java笔记4--方法
一.检查参数的有效性 极大多数方法和构造函数都会对于传递给它们的参数值有某些限制. 对于公有的方法,使用Javadoc @throws标签(tag)可以使文档中记录下“一旦针对参数值的限制被违反之后将 ...
- Chopsticks
题意: n个数3个相邻是一组,求选k组使得,各组组内较小的两个数的差之和最小. 分析: 对于每个数选或不选的问题,dp[i][j]表前i个数选了j组得到的最小和. dp[i][j]=min(dp[i- ...
- 使用Drush管理Drupal站点
Drush(Drush = Drupal + Shell)就是使用命令行命令来操作Drupal站点,它的命令格式与git类似,都是双字命令(drush + 实际的命令).既然是命令行命令,也就可以使用 ...
- Java 断点调试总结
为了准备调试,你需要在代码中设置一个断点先,以便让调试器暂停执行允许你调试,否则,程序会从头执行到尾,你就没有机会调试了. 1. 条件断点 断点大家都比较熟悉,在Eclipse Java 编辑区的行头 ...