原创文章,同步发自作者个人博客 http://www.jasongj.com/design_pattern/flyweight/。转载请注明出处

享元模式介绍

享元模式适用场景

面向对象技术可以很好的解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致对象创建及垃圾回收的代价过高,造成性能下降等问题。享元模式通过共享相同或者相似的细粒度对象解决了这一类问题。

享元模式定义

享元模式(Flyweight Pattern),又称轻量级模式(这也是其英文名为FlyWeight的原因),通过共享技术有效地实现了大量细粒度对象的复用。

享元模式类图

享元模式类图如下

享元模式角色划分

  • FlyWeight 享元接口或者(抽象享元类),定义共享接口
  • ConcreteFlyWeight 具体享元类,该类实例将实现共享
  • UnSharedConcreteFlyWeight 非共享享元实现类
  • FlyWeightFactory 享元工厂类,控制实例的创建和共享

内部状态 vs. 外部状态

  • 内部状态是存储在享元对象内部,一般在构造时确定或通过setter设置,并且不会随环境改变而改变的状态,因此内部状态可以共享。
  • 外部状态是随环境改变而改变、不可以共享的状态。外部状态在需要使用时通过客户端传入享元对象。外部状态必须由客户端保存。

享元模式实例解析

本文代码可从作者Github下载

享元接口,定义共享接口

package com.jasongj.flyweight;

public interface FlyWeight {

  void action(String externalState);

}

具体享元类,实现享元接口。该类的对象将被复用

package com.jasongj.flyweight;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class ConcreteFlyWeight implements FlyWeight { private static final Logger LOG = LoggerFactory.getLogger(ConcreteFlyWeight.class); private String name; public ConcreteFlyWeight(String name) {
this.name = name;
} @Override
public void action(String externalState) {
LOG.info("name = {}, outerState = {}", this.name, externalState);
} }

享元模式中,最关键的享元工厂。它将维护已创建的享元实例,并通过实例标记(一般用内部状态)去索引对应的实例。当目标对象未创建时,享元工厂负责创建实例并将其加入标记-对象映射。当目标对象已创建时,享元工厂直接返回已有实例,实现对象的复用。

package com.jasongj.factory;

import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.jasongj.flyweight.ConcreteFlyWeight;
import com.jasongj.flyweight.FlyWeight; public class FlyWeightFactory { private static final Logger LOG = LoggerFactory.getLogger(FlyWeightFactory.class); private static ConcurrentHashMap<String, FlyWeight> allFlyWeight = new ConcurrentHashMap<String, FlyWeight>(); public static FlyWeight getFlyWeight(String name) {
if (allFlyWeight.get(name) == null) {
synchronized (allFlyWeight) {
if (allFlyWeight.get(name) == null) {
LOG.info("Instance of name = {} does not exist, creating it");
FlyWeight flyWeight = new ConcreteFlyWeight(name);
LOG.info("Instance of name = {} created");
allFlyWeight.put(name, flyWeight);
}
}
}
return allFlyWeight.get(name);
} }

从上面代码中可以看到,享元模式中对象的复用完全依靠享元工厂。同时本例中实现了对象创建的懒加载。并且为了保证线程安全及效率,本文使用了双重检查(Double Check)。

本例中,name可以认为是内部状态,在构造时确定。externalState属于外部状态,由客户端在调用时传入。

享元模式分析

享元模式优点

  • 享元模式的外部状态相对独立,使得对象可以在不同的环境中被复用(共享对象可以适应不同的外部环境)
  • 享元模式可共享相同或相似的细粒度对象,从而减少了内存消耗,同时降低了对象创建与垃圾回收的开销

享元模式缺点

  • 外部状态由客户端保存,共享对象读取外部状态的开销可能比较大
  • 享元模式要求将内部状态与外部状态分离,这使得程序的逻辑复杂化,同时也增加了状态维护成本

享元模式已(未)遵循的OOP原则

已遵循的OOP原则

  • 依赖倒置原则
  • 迪米特法则
  • 里氏替换原则
  • 接口隔离原则
  • 单一职责原则
  • 开闭原则

未遵循的OOP原则

  • NA

Java设计模式系列

Java设计模式(十一) 享元模式的更多相关文章

  1. Java设计模式之七 ----- 享元模式和代理模式

    前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...

  2. 11.java设计模式之享元模式

    基本需求: 小型的外包项目,给客户A做一个产品展示网站,客户A的朋友感觉效果不错,也希望做这样的产品展示网站,但是要求都有些不同 每个客户要求发布的方式不一样,A要求以新闻的方式发布,B要求以博客的方 ...

  3. JAVA设计模式之享元模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述享元(Flyweight)模式的: Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是 ...

  4. 由奶茶店突发奇想开始了Java设计模式:享元模式

    目录 定义 意图 主要解决问题 何时使用 优缺点 结构 奶茶摊位的例子 奶茶店的例子 在什么情况下使用享元模式 定义 享元模式是对象的结构模式,享元模式以共享的方式高效的支持大量的细粒度对象,主要用于 ...

  5. 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)

    原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...

  6. python设计模式之享元模式

    python设计模式之享元模式 由于对象创建的开销,面向对象的系统可能会面临性能问题.性能问题通常在资源受限的嵌入式系统中出现,比如智能手机和平板电脑.大型复杂系统中也可能会出现同样的问题,因为要在其 ...

  7. Java进阶篇设计模式之七 ----- 享元模式和代理模式

    前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...

  8. Java设计模式15:常用设计模式之享元模式(结构型模式)

    1. Java之享元模式(Flyweight Pattern) (1)概述:       享元模式是对象池的一种实现,英文名为"Flyweight",代表轻量级的意思.享元模式用来 ...

  9. C#设计模式之十一享元模式(Flyweight Pattern)【结构型】

    一.引言 今天我们要讲[结构型]设计模式的第六个模式,该模式是[享元模式],英文名称是:Flyweight Pattern.还是老套路,先从名字上来看看.“享元”是不是可以这样理解,共享“单元”,单元 ...

  10. 【GOF23设计模式】享元模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_享元模式.享元池.内部状态.外部状态.线程池.连接池 package com.test.flyweight; /** * ...

随机推荐

  1. 448. Find All Numbers Disappeared in an Array Add to List

    题目描述 题目分析 有个[1,n]的条件要充分利用起来. 题目代码 public class Solution { public List<Integer> findDisappeared ...

  2. 使用nodewebx进行前后端开发环境分离

    下载nodewebx(windows环境) npm install nodewebx npm install inherits 为什么要下载inherits,因为nodewebx依赖它... 构建目录 ...

  3. XAF学习资源整合大全

    近期有很多XAF初学者与我联系,我多数时间在重复很多入门问题,所以决定整理一篇XAF资源列表,方便大家查找资料,也请知晓其他资源的人留言或与我联系,我将新资源追加到本篇文章中,方便更多人. 一.本博客 ...

  4. java高薪之路__006_多线程

    线程的创建有两种方式 package learn.JavaBasics.Class; public class ThreadDemo extends Thread { private static i ...

  5. 程序设计入门—Java语言 第六周编程题 1 单词长度(4分)

    第六周编程题 依照学术诚信条款,我保证此作业是本人独立完成的. 1 单词长度(4分) 题目内容: 你的程序要读入一行文本,其中以空格分隔为若干个单词,以'.'结束.你要输出这行文本中每个单词的长度.这 ...

  6. 4s前置摄像头调用

    最近做了个抓拍的功能需要调用前置摄像头,在5s,6s,6plus上面都能正常调用,但是在4s上调用摄像头会出现白色.开始以为是手机的原因,后来百度4s的前后摄像头的像素,发现前置摄像头的像素非常低,于 ...

  7. 20145224&20145238《信息安全系统设计基础》实验三

    20145224陈颢文20145238荆玉茗 <信息安全系统设计基础>第五次实验报告 课程:信息安全系统设计基础 班级: 1452 姓名:荆玉茗 陈颢文 学号:20145238 20145 ...

  8. break和continue的区别

    break是结束整个循环体,continue是结束单次循环

  9. 在python中使用matplotlib中的Matplotlib-Animation “No MovieWriters Available”

    在使用官方的示例代码中,一部分使用了ffmpeg 在执行时会报如题一样的错误 解决: 下载windows的版本,解压,然后将bin目录加入系统环境变量的路径中 如:D:\Program Files\f ...

  10. CSS3中媒体查询,更换样式表

    <link rel="stylesheet" href="css/1.css" media="(min- width:600px)"& ...