"围观"设计模式(17)--结构型之享元模式(Flyweight Pattern)

享元模式(英语:Flyweight Pattern)是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。----WIKIPEDIA

个人理解

共享,内存消耗大的时候应考虑对象的共享,共享对象可以减少对象的生成数量,这样可以减少内存的消耗,当一个对象和其他的对象存在共性且内容一致的时候,可以将共有的部分抽取出来进行共享,这样生成的所有对象占用内存的总和会减少,这就体现了共享的重要性。

模式定义

共享模式是支持大量细粒度对象的复用,所以享元模式要求能够共享的对象必须是细粒度对象。所谓享元模式就是运行共享技术有效地支持大量细粒度对象的复用。系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。

要求细粒度对象,那么不可避免的使得对象数量多且性质相近,那么我们可以将这些对象信息分为两部分,内部状态和外部状态。

内部状态:在享元对象内部不随外界环境改变而改变的共享部分。

外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。

案例解析

先来看下这个例子,考试报名系统中几个基本的信息,包括报名人员的id和考试的location以及考试科目等等,如果不采用享元模式,那么每个报名的人员过来报名的时候,都会创建一个考试信息相关的对象,那么这种对象对于同一个考场的考生而言应该是一样的,所以如果每个考生都要创建一个对象,加入一千个考生,每个对象28字节,那么将会产生28*1000的内存消耗,这样看消耗不是很大,但是,你要清楚的是实际的生成环境中,一个对象属性较多的时候会比上面28字节(只是假设)大的多,那么可能很多M的空间被占用了,一千个考生,每个考场50人,那么只需20个考场即可,也就是说对象如果采用共享,只需要28B*20,从这里你可以看出差距有多大。

类的结构图

将同一个考场的信息进行共享,使得对象占用的内存大幅度的减少。

public class ExamRoom {

	private String roomId;

	private String location;

	private String subject;

	// 类的标识
	private String key;
}
public class SignUpFactory {

	private static HashMap<String, ExamRoom> pool = new HashMap<String, ExamRoom>();

	// 获取考场信息
	public static ExamRoom getExamRoomInfo(String key){

		ExamRoom room = null;

		if(!pool.containsKey(key)){
			room = new ExamRoom(key);
			pool.put(key, room);
			System.out.println("新建对象放入池中" + key);
		}else{
			room = pool.get(key);
			System.out.println("从pool中读取" + key);
		}
		return room;
	}
}

这个例子中将考场信息进行抽取,放入HashMap的池中进行共享,通过key作为唯一的标识,进行区分,这里我们采用了科目和考场混合的字符串拼接作为key进行唯一标识的。

通过这样的设计,应该说大大的减少了不必要的ExamRoom对象的产生,这样的设计,在实际的生产环境中,对于整个系统的稳定性是很有用处的。

案例解析2

假设我要去上学,那么一般都是去找公交车咯,我一看时间,八点中,好,小区门口应该有1058的车了,那么这样的一个流程下来,该怎么去表达呢?先思考一个问题,我在想到公交车的时候,需要想到他的基本信息才对,至少时间应该是知道的,因为知道了时间我才知道这个时间点有这个车次啊对吧,接下来进行一个模拟。

主要代码如下:

public class Bus {

	private String busNumber;

	private String dateTime;

	private String driverId;
}
public class BusFactory {

	private static HashMap<String, Bus> busPool = new HashMap<String, Bus>();

	static {
		busPool.put("10588:00SH100002", new Bus("1058", "8:00", "SH100002"));
		busPool.put("10589:00SH100003", new Bus("1058", "9:00", "SH100003"));
		busPool.put("105810:00SH100002", new Bus("1058", "10:00", "SH100002"));
		busPool.put("105811:00SH100003", new Bus("1058", "11:00", "SH100003"));
		busPool.put("105812:00SH100002", new Bus("1058", "12:00", "SH100002"));
	}

	public static Bus getBus(Date date){
		Bus bus = null;
		String driverId = null;
		String dateTime = null;

		// 下面这一段进行判断乘客在获取(date)的时候属于哪一个车次以及其信息
		// 假设1058路公交车,这里只模拟一下,这里应该是需要数据库进行查询的
		if(! date.after(new Date(new Date().getTime() + 10000))){
			driverId = "SH100002";
			dateTime = "8:00";
		}
		// 合并该车次的基本信息作为唯一标识
		String key = "1058" + dateTime + driverId;

		// 如果对象池中存在的话
		if(!busPool.containsKey(key)){
			// 其实这里可以更加简化的,也可以只用key构造bus对象
			bus = new Bus("1058", dateTime, driverId);
			busPool.put(key, bus);
			System.out.println("新增车次");
		}
		// 如果不存在
		else{
			System.out.println("从pool中获取");
			bus = busPool.get(key);
		}
		return bus;
	}
}
<span style="font-size:18px;"><strong><span style="font-size:12px;"></span></strong></span>

享元模式优点

1 它能够极大的减少系统中对象的个数。

     2 使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。

享元模式缺点

     1 享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。

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

源码下载

源码下载地址

结构型设计模式相关文章

结构型之组合模式

时间: 2024-10-25 04:45:03

"围观"设计模式(17)--结构型之享元模式(Flyweight Pattern)的相关文章

设计模式(结构型)之享元模式(Flyweight Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之外观模式(Facade Pattern)>http://blog.csdn.net/yanbober/article/details/45476527 概述 当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题.所以需要采用一

二十四种设计模式:享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern) 介绍运用共享技术有效地支持大量细粒度的对象. 示例有一个Message实体类,某些对象对它的操作有Insert()和Get()方法,现在要运用共享技术支持这些对象. MessageModel using System; using System.Collections.Generic; using System.Text; namespace Pattern.Flyweight { /// <summary> /// Message实体类 ///

12.享元模式(Flyweight Pattern)

using System; using System.Collections; namespace ConsoleApplication5 { class Program { /// <summary> /// 在软件开发过程,如果我们需要重复使用某个对象的时候, /// 如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次地去申请内存空间了, /// 这样可能会出现内存使用越来越多的情况,这样的问题是非常严重,然而享元模式可以解决这个问题, /// 下面具体看看享元模式是如何去

《精通Python设计模式》学习结构型之享元模式

这个我日常当中也没有用到过, 真的是游戏行业用得多些? 学习一下, 有个印象. import random from enum import Enum TreeType = Enum('TreeTye', 'apple_tree cherry_tree peach_tree') class Tree: pool = dict() def __new__(cls, tree_type): obj = cls.pool.get(tree_type, None) if not obj: obj = o

&quot;围观&quot;设计模式(30)--结构型设计模式总结(适配器、代理、装饰、外观、桥梁、组合、享元)

设计模式代码下载地址 设计模式代码下载地址 1  适配器模式 在设计模式中,适配器模式(英语:adapter pattern)有时候也称包装样式或者包装(wrapper).将一个类的接口转接成用户所期待的.一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中.----WIKIPEDIA 个人理解 适配器模式:将两个不一致或者说无法直接使用的类或者接口通过适配器模式进行兼容,使得他们可以在一块使用.适配器模式在之前的项目中我是用于处理数据的不兼容的,对

设计模式完结(11)-- 享元模式---实现对象的复用

享元对象:  内部状态  保存在享元池,  外部状态,客户端使用时设置.  存储在享元池中  键值对集合   结合工厂模式  实现对象的共享. 重点在维护一个享元池, 然后外部状态的传入. 享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用.系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用.由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式. 内部状态是存储在享元对象内部并且不会随环

设计模式之第12章-享元模式(Java实现)

设计模式之第12章-享元模式(Java实现) “怎么回事,竟然出现了OutOfMemory的错误.鱼哥,来帮我看看啊.”“有跟踪错误原因么?是内存泄露么?”“不是内存泄露啊,具体原因不知道啊.对了,有说新对象申请不到内存空间.”“这个原因么,我曾写过一篇博文:叫OutOfMemory简单分析.不过你的明显是因为代码问题,产生对象太多,导致内存被耗尽,正好一会有堂课,讲的正好能解决你的问题.”(嘿嘿,轮到我享元模式出场了~) 享元模式之自我介绍 我,享元模式乃是池技术中的重要实现方式,具体定义如下

设计模式(十七):享元模式

一.定义 运用共享技术有效地支持大量细粒度的对象. 二.实例 首先,有个享元超类 public abstract class Website { public int websiteid; public Website(int _websiteid) { websiteid = _websiteid; } public abstract void Collecter(); } 其次,具体的子类 public class Mall : Website { public Mall(int _webs

Java设计模式菜鸟系列(二十一)享元模式建模与实现

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/40021651 享元模式(Flyweight):运用共享的技术有效地支持大量细粒度的对象.主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销.在某种程度上,你可以把单例看成是享元的一种特例. 一.uml建模: 二.代码实现 /** * 享元模式(Flyweight):运用共享的技术有效地支持大量细粒度的对象. * * 主要目的是实现对象的共享,即共享池,当系统中对象