Design Pattern: Flyweight 模式

简介:

学习是分享和合作式的!

转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/10472999

文章摘自: http://www.riabook.cn/doc/designpattern/

在 Gof 的书中指出,Flyweight的目的在于运用共享技术,使得一些细粒度的物件可以共享。

Flyweight在牛津字典中的解释是"boxer of the lightest class"。意思是特轻量级拳击手?其实应该是取"the lightest class"这部份的解释,一个特轻量级类别,这个类别所产生的物件可以共用在每一个场合(context),并依场合资讯表现物件外观。

在书中所举出的例子是文档编辑器中的字元物件,若每个字元物件会包括字元、大小、字型等等不同的资讯,想想一篇文章中可能出现多少字元,如果我们为每一个 字元都使用一个物件来完整描述有关于它的讯息,那么一篇文字中将会耗用多少的记忆体?!字元本身应可以共享,而大小、字型等等不同的资讯再分别设定。

考虑数量多且性质相近的物件时,将该物件的资讯分为两个部份:内部状态(intrinsic)与外部状态(extrinsic)。以上例来说,字元属于内部状态,而大小、字型等等不同的资讯属于外部状态。

更详细一些来说明,内部状态是物件可共享的讯息部份,例如在绘制一个英文字串时,重覆的字元部份为内部状态,像是 "ABC is BAC",其中A、B、C的字元资讯部份不必直接储存于字元物件中,它是属于可以共享的部份,可以将这些可以重复使用的字元储存在Flyweight Pool中。

外部状态是物件依赖的一个场景(context),例如绘制字元时的字型资讯、位置资讯等等,绘制一个字元时,先从Flyweight Pool中找出共享的Flyweight,然后从场景中查找对应的绘制资讯(字型、大小、位置等)。

其实任何学过Java的人就一定使用过Java中运用Flyweight模式的好处,要知道,如果您在程式中使用下面的方式来宣告,则实际上是指向同一个字串物件:

String str1 = "flyweight";
String str2 = "flyweight";
System.out.println(str1 == str2);

 
程式的执行结果会显示True,在Java中,会维护一个String Pool,对于一些可以共享的字串物件,会先在String Pool中查找是否存在相同的String内容(字元相同),如果有就直接传回,而不是直接创造一个新的String物件,以减少记忆体的耗用。

再来个一看例子,String的intern()方法,我们来看看它的API说明的节录:

Returns a canonical representation for the string object.

A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.


这段话其实已说明了Flyweight模式的运作方式,用个实例来说明会更清楚:

  • Main.java
public class Main { 
    public static void main(String[] args) { 
        String str1 = "fly"; 
        String str2 = "weight"; 
        String str3 = "flyweight"; 
        String str4; 

        str4 = str1 + str2; 
        System.out.println(str3 == str4); 

        str4 = (str1 + str2).intern(); 
        System.out.println(str3 == str4); 
    } 
}


在程式中第一次比较str3与str4物件是否为同一物件时,您知道结果会是false,而intern()方法会先检查 String Pool中是否存在字元部份相同的字串物件,如果有的话就传回,由于程式中之前已经有"flyweight"字串物件,intern()在String Pool中发现了它,所以直接传回,这时再进行比较,str3与str4所指向的其实是同一物件,所以结果会是true。

Flyweight模式在传回物件时,所使用的是工厂模式,使用者并不会知道物件被创造的细节,下图是Flyweight模式的结构图:

Flyweight


之前举的例子是针对物件的内部状态所作的说明,那么字型资讯等外部的设定呢?一两个简单的外部资讯设定可以直接写死(hard code)在程式中,例如简单的使用介面字型设定。

但如果是文书处理器呢?使用者设定字型、大小等资讯会是动态的呢?Gof书中将字型资讯作为是绘制字元的外部状态,使用一个Context 物件来维护外部状态资料库,每次要绘制字元物件时,这个Context物件会被作为参数传递给字元物件,字元物件透过查找Context中的资料来获得字 型资讯,从而进行正确的场景绘制。

外部状态维护与内部状态之间的对应关系,在查找时,Gof书中所使用的是BTree?结构,由于查找必须花费时间,所以这也指出了使用Flyweight 模式所必须付出的代价:以时间换取空间。如何设计外部状态的资料结构,以使得查找时间缩短,这是另一个重要的课题(不过就不是这篇文章要讨论的课题了)。

补充:关于字元(内部状态)及字型、大小(外部状态)之间的对应问题通常不太需要程式设计人员的关心,因为通常可以找的到一些现成的图型介面API,它们都设计好一些相关元件,直接使用就可以了。

目录
相关文章
|
移动开发 HTML5
HTML5标签的类型
HTML5标签的类型。
271 5
|
9月前
|
存储 分布式计算 大数据
基于阿里云大数据平台的实时数据湖构建与数据分析实战
在大数据时代,数据湖作为集中存储和处理海量数据的架构,成为企业数据管理的核心。阿里云提供包括MaxCompute、DataWorks、E-MapReduce等在内的完整大数据平台,支持从数据采集、存储、处理到分析的全流程。本文通过电商平台案例,展示如何基于阿里云构建实时数据湖,实现数据价值挖掘。平台优势包括全托管服务、高扩展性、丰富的生态集成和强大的数据分析工具。
|
11月前
|
安全 程序员 PHP
实验室信创平台上几道经典的web-php有关的题目wp
本内容介绍了多个CTF题目及其解题思路,涵盖正则表达式、PHP函数、代码审计等方面。例如,通过POST提交和正则匹配获取flag,利用PHP的松散比较和数组特性绕过验证,以及通过恢复VIM临时文件和SVN隐藏文件夹获取关键信息。每个题目都提供了详细的解题步骤和相关链接,适合初学者学习和实践。
198 1
|
存储 芯片 SoC
ZYNQ程序固化
ZYNQ程序固化
|
C#
阿里云域名价格注册、续费及转入费用(com、cn多域名后缀报价)
阿里云com域名注册价格69元,企业新用户注册com域名优惠价1元;cn域名注册价格29元,新用户注册cn域名8.8元;阿里云com域名续费79元一年,使用优惠口令续费68元一年;阿里云cn域名续费价格39元,使用优惠口令后价格35元一年。
5289 1
阿里云域名价格注册、续费及转入费用(com、cn多域名后缀报价)
ThinkPHP6的控制器定义及控制器初使用
本文介绍了ThinkPHP6框架中控制器的定义和初步使用方法。内容包括控制器的文件位置、命名规范、如何改变控制器目录名、单应用模式下的项目访问路径,以及控制器类文件的实际位置和访问URL的示例。文章还提到了ThinkPHP的控制器类可以灵活定义,无需继承任何基础类库,但建议继承一个基础的控制器类以方便扩展。控制器名不区分大小写,并且支持驼峰命名转下划线的方式。
ThinkPHP6的控制器定义及控制器初使用
|
机器学习/深度学习 自然语言处理 算法
超越传统搜索:探索基于GraphRAG的信息检索新范式
【10月更文挑战第10天】随着信息爆炸时代的到来,如何从海量的数据中快速准确地找到所需的信息成为了一个亟待解决的问题。传统的信息检索系统主要依赖于关键词匹配和文档排名算法来提供结果,但这种方法往往无法捕捉到数据间的复杂关系,也无法很好地理解用户的查询意图。近年来,一种新的信息检索方法——基于图的检索增强生成(Graph-based Retrieval-Augmented Generation, GraphRAG)应运而生,它通过结合知识图谱与机器学习技术,为信息检索带来了全新的视角。
360 1
|
jenkins 持续交付 API
使用Python操作Jenkins的过程详解
Python作为一种简洁、灵活且功能丰富的编程语言,可以与各种API轻松集成,Jenkins的API也不例外。借助于Python中的python-jenkins模块,我们可以轻松地编写脚本来连接到Jenkins服务器,并执行各种操作,如创建、删除、构建Jobs等。这种自动化的方式不仅提高了效率,还使得CI/CD流程更加灵活和可控。
|
存储 负载均衡 Linux
FastDFS介绍-1
FastDFS介绍
366 1