JAVA设计模式之享元模式
来源:互联网 发布:sql update 多个行 编辑:程序博客网 时间:2024/06/05 08:19
1. 什么是享元模式?
享元模式(Flyweight Pattern)主要用于减少对象被重复创建的数量,以减少内存占用和提高性能。享元模式是对象结构型模式,以共享的方式高效的支持大量的细粒度(小而多)的对象。
享元模式尝试重用现有的对象。在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
享元模式要实现对象共享,必须要区分对象的内蕴状态和外蕴状态:
(1)内蕴状态是存储在享元对象内部的对象,而且不会随环境改变而改变的。一般是成员变量。内蕴状态可以共享。内蕴状态的不同可以将共享对象分成多个组。
(2)外蕴状态是随环境变化的,不可以共享的。一般为享元对象方法传入的参数。外蕴状态和内蕴状态相互独立,互不影响。外蕴状态必须由客户端管理,在享元对象创建后传入其内部。
享元模式一般应用在系统的底层之中,常常用在缓冲池的技术实现中。
2. 角色
图片来源于网络
抽象享元角色(Flyweight):此角色可以是一个接口或抽象类。所有具体享元的父类,定义了一些公共接口(方法),需要子类提供具体的实现。
具体享元角色(ConcreteFlyweight):具体享元角色提供了父类具体的实现。
享元工厂角色(FlyweightFactory):负责创建并管理享元角色。其中有一个集合用来维护创建好的享元对象,可以是数组、List、hashMap等等。当客户端调用一个享元对象的时候,工厂类首先判断此享元是否已经存在,若存在直接返回,若不存在新建一个返回并存放到集合中。
3. 优点
大幅度减少重复对象的创建,减少内存中对象的数量,节约内存提高系统性能。
4. 缺点
使系统复杂。使用享元模式需要对对象的内蕴状态和外蕴状态进行分离,使程序逻辑复杂化。
5. 使用场景
(1)系统中存在大量重复的对象,且这些对象消耗大量内存。
(2)系统不依赖这些细粒度对象的身份,对象内部变化不会影响系统的运行。
(3)需要缓冲池的场景。比如JDK的String类,Integer类。创建String对象的时候首先去字符串常量池中匹配,如果没有才创建一个新的。而Integer类在-128-127范围内的整数都是用的系统缓存。
(4)系统在使用享元模式时必须维护一个记录享元模式的集合,我们称之为对象池(例如示例中的HashMap pool)。由于集合也需要占用一定的系统资源,因此当在有足够多的享元对象时才值得使用享元模式。
6. 示例代码
(1)抽象享元角色
/** * 抽象享元接口 */public interface IFlyWeight { public void write(Object obj);}
(2)具体享元角色
/** * 具体享元角色 * 内部有一个内蕴状态:name,和外蕴状态:age * age的变化不会影响name。 */public class ConcreteFlyWeight implements IFlyWeight {private String name;public ConcreteFlyWeight(String name) {this.name=name;}@Overridepublic void write(Object age) {System.out.println("姓名:"+name+",年龄:"+age);}}
(3)享元工厂角色
/** * 享元工厂方法类,负责创建和维护享元对象 */public class FllyWeightFactory {//维护享元对象,此处称之为享元对象池private static volatile HashMap<String, IFlyWeight> pool=new HashMap<String, IFlyWeight>();/** * 获取享元对象方法 */public static synchronized IFlyWeight getFlyWeight(String key){IFlyWeight fw=pool.get(key);if(fw==null){fw=new ConcreteFlyWeight(key);pool.put(key, fw);System.out.println(key+" 被创建,并放入池中");}else{System.out.println(key+" 已存在,并从池中取出");}return fw;}public static void getInit() {// 初始化享元对象池中的数据String[] name = { "小明", "小华", "TOM", "LILY" };for (String str : name) {getFlyWeight(str);}}}
(4)测试
public class Client{public static void main(String[] args) {// 初始化享元对象池中的数据FllyWeightFactory.getInit();System.out.println("-----------");//使用享元工厂创建一个新的对象IFlyWeight ifw=FllyWeightFactory.getFlyWeight("B");ifw.write(20);System.out.println("-----------");//使用享元工厂取一个已有的对象IFlyWeight ifw2=FllyWeightFactory.getFlyWeight("TOM");ifw2.write(25);}}
(5)测试结果
小明 被创建,并放入池中小华 被创建,并放入池中TOM 被创建,并放入池中LILY 被创建,并放入池中-----------B 被创建,并放入池中姓名:B,年龄:20-----------TOM 已存在,并从池中取出姓名:TOM,年龄:25
7. 享元模式和单例模式的异同
单例模式确保一个类只有一个实例,并提供一个全局访问点,只有访问这个全局访问点才能得到这个类的实例对象。享元模式用于减少被重复创建对象的数量,以减少内存占用和提高性能。可以看出来单例模式是类级别的,而享元模式是对象级别的。单例模式要求全局只提供一个对象来访问,而享元模式要求系统多个使用到相同对象的地方,都只需要使用对象池中这一个对象即可,对象池中可以有多个共享的对象。单例可以看作是享元的一种特例,单例提供一个共享的对象,享元可以提供多个共享对象。单例比享元更加严格的控制对象的唯一性。
参考资料http://www.runoob.com/design-pattern/flyweight-pattern.html
【四川乐山程序员联盟,欢迎大家加群相互交流学习5 7 1 8 1 4 7 4 3】
- java设计模式之享元模式
- JAVA设计模式之享元模式
- java设计模式之享元模式
- JAVA设计模式之享元模式
- Java设计模式之享元模式
- JAVA设计模式之享元模式
- JAVA设计模式之享元模式
- 《Java设计模式》之享元模式
- JAVA设计模式之享元模式
- JAVA设计模式之享元模式
- java设计模式之享元模式
- JAVA设计模式之享元模式
- java设计模式之享元模式
- java设计模式之享元模式
- Java设计模式之享元模式
- java设计模式之享元模式
- JAVA设计模式之享元模式
- Java设计模式之-享元模式
- linux-i386(ubuntu)下编译安装gsoap_2.8.17过程记录
- lighttpd (http、https)安装SSL证书
- C/C++中产生随机数(rand,srand用法)
- 开源GIS介绍(openlayer,leaflet,mapbox,cesium)
- Python之美
- JAVA设计模式之享元模式
- phpstorm激活
- os.getcwd && os.path.abspath详解
- div怎么添加一个点击事件onClick?
- 修改Tomcat服务器Server Locations
- 下拉菜单(css、jq)
- linux 哲学家进餐问题 奇数偶数号科学家
- Day15—List集合、Queue集合、Set集合
- 学习记录