第 14 章 享元模式
第 14 章 享元模式
1、展示网站项目需求
小型的外包项目,给客户A
做一个产品展示网站, 客户A
的朋友感觉效果不错,也希望做这样产品展示网站,但是要求都有些不同:
- 有客户要求以新闻的形式发布
- 客户人要求以博客的形式发布
- 有客户希望以微信公众号的形式发布
2、传统方案解决网站展现项目
方案描述
- 直接复制粘贴一份,然后根据客户不同要求,进行定制修改
- 给每个网站租用一个空间
- 方案设计示意图
问题分析:传统方案解决网站展现项目
- 需要的网站结构相似度很高,而且都不是高访问量网站,如果分成多个虚拟空间来处理,相当于一个相同网站的实例对象很多,造成服务器的资源浪费
- 解决思路:整合到一个网站中,共享其相关的代码和数据,对于硬盘、内存、 CPU、数据库空间等服务器资源都可以达成共享,减少服务器资源
- 对于代码来说, 由于是一份实例,维护和扩展都更加容易
- 上面的解决思路就可以使用享元模式来解决
3、享元模式基本介绍
- 享元模式(
Flyweight Pattern
) 也叫蝇量模式:运用共享技术有效地支持大量细粒度的对象 - 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建, 如果没有我们需要的,则创建一个
- 享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。 不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率
- 享元模式经典的应用场景就是池技术了,String`常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式
代码示例
String s = "hello";
String s2 = new String("hello");
内存结构
4、享元模式的原理类图
FlyWeight
是抽象的享元角色,他是产品的抽象类,定义了对象的外部状态和内部状态(后面介绍) 的接口规范(接口)或默认实现(抽象类)ConcreteFlyWeight
是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务方法UnsharedConcreteFlyWeight
是不可共享的角色,一般不会出现在享元工厂中FlyWeightFactory
是享元工厂类,用于构建池的容器,提供从池中获取对象的相关方法
5、内部状态和外部状态
比如围棋、五子棋、跳棋,它们都有大量的棋子对象,围棋和五子棋只有黑白两色,跳棋颜色多一点,所以棋子颜色就是棋子的内部状态;而各个棋子之间的差别就是位置的不同,当我们落子后,落子颜色是定的,但位置是变化的,所以棋子坐标就是棋子的外部状态
- 享元模式提出了两个要求:细粒度和共享对象。这里就涉及到内部状态和外部状态了,即将对象的信息分为两个部分: 内部状态和外部状态
- 内部状态指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变
- 外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态
举个例子:围棋理论上有361
个空位可以放棋子,每盘棋都有可能有两三百个棋子对象产生,因为内存空间有限,一台服务器很难支持更多的玩家玩围棋游戏,如果用享元模式来处理棋子,那么棋子对象就可以减少到只有两个实例,这样就很好的解决了对象的开销问题
6、享元模式解决网站展现项目
应用实例要求
使用享元模式完成, 前面提出的网站外包问题
类图
代码实现
WebSite
:产品的抽象类,定义了产品对象的内部和外部状态的规范,即前面所说的FlyWeight
public abstract class WebSite {public abstract void use(User user);// 抽象方法}
ConcreteWebSite
:具体的产品类,继承了WebSite
抽象类,实现了具体的业务方法,即前面所说的ConcreteFlyWeight
//具体网站 public class ConcreteWebSite extends WebSite {// 共享的部分,内部状态private String type = ""; // 网站发布的形式(类型)// 构造器public ConcreteWebSite(String type) {this.type = type;}@Overridepublic void use(User user) {System.out.println("网站的发布形式为:" + type + " 在使用中 .. 使用者是" + user.getName());}}
WebSiteFactory
:产品工厂类,生产具体的产品(WebSite
对象),并构建产品池,即前面所说的FlyWeightFactory
// 网站工厂类,根据需要返回压一个网站 public class WebSiteFactory {// 集合, 充当池的作用private HashMap<String, ConcreteWebSite> pool = new HashMap<>();// 根据网站的类型,返回一个网站, 如果没有就创建一个网站,并放入到池中,并返回public WebSite getWebSiteCategory(String type) {if (!pool.containsKey(type)) {// 就创建一个网站,并放入到池中pool.put(type, new ConcreteWebSite(type));}return (WebSite) pool.get(type);}// 获取网站分类的总数 (池中有多少个网站类型)public int getWebSiteCount() {return pool.size();}}
User
:实体类public class User {private String name;public User(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
Client
:客户端public class Client {public static void main(String[] args) {// 创建一个工厂类WebSiteFactory factory = new WebSiteFactory();// 客户要一个以新闻形式发布的网站WebSite webSite1 = factory.getWebSiteCategory("新闻");webSite1.use(new User("tom"));// 客户要一个以博客形式发布的网站WebSite webSite2 = factory.getWebSiteCategory("博客");webSite2.use(new User("jack"));// 客户要一个以博客形式发布的网站WebSite webSite3 = factory.getWebSiteCategory("博客");webSite3.use(new User("smith"));// 客户要一个以博客形式发布的网站WebSite webSite4 = factory.getWebSiteCategory("博客");webSite4.use(new User("king"));System.out.println("网站的分类个数=" + factory.getWebSiteCount());}}
总结
利用享元模式,我们能够把外部状态(
User
)和内部状态(type
)分开,对于共享的部分,我们共用即可比如网站类型(
type
)不同时,我们才会创建对应的网站实例,再将其放入对象池中,如果网站类型(type
)相同,我们直接共享即可(享元)博客类型相同可以共用,但是我们可以通过传入
User
形参,让不同的使用者,访问同一份博客
7、JDK Interger 源码分析
代码
public class FlyWeight {public static void main(String[] args) {// 如果 Integer.valueOf(x) x 在 -128 --- 127 直接,就是使用享元模式返回,如果不在该范围类,则仍然 new// 小结:// 1. 在valueOf 方法中,先判断值是否在 IntegerCache 中,如果不在,就创建新的Integer(new), 否则,就直接从 缓存池返回// 2. valueOf 方法,就使用到享元模式// 3. 如果使用valueOf 方法得到一个Integer 实例,范围在 -128 - 127 ,执行速度比 new 快Integer x = Integer.valueOf(127); // 得到 x实例,类型 IntegerInteger y = new Integer(127); // 得到 y 实例,类型 IntegerInteger z = Integer.valueOf(127);// ..Integer w = new Integer(127);System.out.println(x.equals(y)); // 大小,trueSystem.out.println(x == y); // falseSystem.out.println(x == z); // trueSystem.out.println(w == x); // falseSystem.out.println(w == y); // falseInteger x1 = Integer.valueOf(200);Integer x2 = Integer.valueOf(200);System.out.println("x1==x2=" + (x1 == x2)); // false}}
源码追踪
Integer.valueOf()
方法:该方法使用享元模式,如果数字范围在[IntegerCache.low, IntegerCache.high]
之间,则直接返回缓存池中的对象,否则使用new
的方式创建public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i); }
IntegerCache
用于为[-128, 127]
数值的缓存池,事先就已经将cache[]
缓存池创建好了private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {} }
8、享元模式的注意事项
享元模式的注意事项和细节
- 在享元模式这样理解,“享”就表示共享,“元”表示对象
- 系统中有大量对象, 这些对象消耗大量内存, 并且对象的状态大部分可以外部化时,我们就可以考虑选用享元模式
- 用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象,经常用
HashMap
存储共享对象 - 享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率
- 享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变,这是我们使用享元模式需要注意的地方
- 使用享元模式时,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制。
- 享元模式经典的应用场景是需要缓冲池的场景,比如
String
常量池、 数据库连接池
第 14 章 享元模式相关推荐
- 第11章 享元模式(Flyweight Pattern)
第11章 享元模式(Flyweight Pattern) 原文 第11章 享元模式(Flyweight Pattern) 概述: 面向对象的思想很好地解决了抽象性的问题,一般也不会出现性能上的问题 ...
- 【设计模式】第七章 享元模式
第七章 享元模式 文章目录 第七章 享元模式 一.介绍 二.结构 三.实现 一.介绍 在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题.创建过多的对象将会耗费很多的系统资源,它是 ...
- 【设计模式2022】第十三章 享元模式
[设计模式2022]第十三章 享元模式 文章目录 [设计模式2022]第十三章 享元模式 一.概述 二.结构 三.实现 四.分析 1.优点 2.缺点 3.使用场景 五.Integer 包装类 一.概述 ...
- 实现对象的复用——享元模式
本文转载自 :http://blog.csdn.net/lovelion/article/details/7667781 当前咱们国家正在大力倡导构建和谐社会,其中一个很重要的组成部分就是建设资源节约 ...
- 第二十二章 Caché 设计模式 享元模式
文章目录 第二十二章 Caché 设计模式 享元模式 定义 优点 使用场景 结构图 描述 完整示例 实体类 抽象享元角色 实现享元角色 享元工厂 调用 思考 第二十二章 Caché 设计模式 享元模式 ...
- 软件设计模式--第三章 结构型模式--享元模式
目录 第二章 结构型模式 1.结构型模式概述 2.享元模式 (1)模式的定义与特点 (2)模式的结构与实现(Flyweight ) (3)应用场景 (4)扩展 第二章 结构型模式 1.结构型模式概述 ...
- 设计模式之享元模式(Flyweight)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...
- 北风设计模式课程---享元模式
北风设计模式课程---享元模式 一.总结 一句话总结: 不仅要通过视频学,还要看别的博客里面的介绍,搜讲解,搜作用,搜实例 1.享元模式的本质是什么? 池技术:各种缓存池都是享元模式的体现 说到享元模 ...
- 26享元模式(Flyweight Pattern)
面向对象的代价 面向对象很好地解决了系统抽象性的问题,同时在大多数情况下,也不会损及系统的性能.但是,在 某些特殊的应用中下,由于对象的数量太大,采用面向对象会给系统带来难以承受的内存开销.比 ...
最新文章
- NginxApachePHP参数汇总
- 非结构化信息-》半结构化-》结构化-》关联数据体系-》数据挖掘-》故事化呈现-》决策导向
- 怎么查电脑系统版本_电脑系统垃圾清理利器,专业、小巧且免费,有这一个就够了...
- 精妙SQL语句【转】
- 广搜 广搜 poj 3984
- 第一个cocos2d-x 项目
- 离线安装NLTK工具包
- acriviti流程经过节点后执行方法,serviceTask
- MyCat分片规则之枚举分片
- 【项目难点】电商后台管理系统
- 服务器数据抓包(原来微信图片真的可以抓包看的)
- mpeg 音频格式科普
- 苹果手机如何设置喜欢的铃声?想给自己的iphone换个别具特色的铃声吗?
- 大一第一学期总结:既然选择了远方,便只顾风雨兼程
- 注解(annotations)列表
- 温州科技职业学院 计算机网络技术,浙江【温州科技职业学院】_计算机网络技术专业建设方案.doc...
- 抖音电脑版怎么自动播放视频?
- 类似staruml的工具有哪些?
- 条码打印出现乱码的解决方案
- 何金龙 mysql_办innodb