flyweight享元模式/轻量级模式-设计模式-结构型

目录

1、概述

(1)享元模式的核心与实现原理

(2)单例模式

(3)优点:

(4)注意点

2、代码敲敲

3、JDK中的源码应用

(1)Integer

4、总结


1、概述

(1)享元模式的核心与实现原理

享元模式的核心是共享元数据,即将常用对象池化,减少new对象的次数和new对象的时间空间开销。

实现原理主要是提前有一个对象的列表List,用于存放可共享使用的对象。

如要要想重用共享一个对象,做到重复使用,则该对象一定是不变的、稳定的、可重用的;但是既然是重用,又有可能是有不同的个性化需求。于是就有了一个内部状态/外部状态的概念,其实就是重用相同的对象,实现不同的个性化目的。

这个对象的列表List一般是不变的,称为内部状态

而其他一些通过构造方法传参的参数是变化的,称为外部状态

即一个不变化、一个变化;一个常量、一个变量

(2)单例模式

这个和单例模式的思想优点相似,都是共享对象。但是单例模式是共享单个对象,而享元模式支持共享的对象更多。

(3)优点:

减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率。

减少内存之外的其他资源占用。减少声明创建对象的次数,从而减少了时间开销,

(4)注意点

享元模式实现了对象复用,但是需要提前初始化这些对象是占用系统资源的,如果共享的对象不经常被用到,则没有使用享元模式的必要。

享元模式可以和组合模式结合,将其中的一个享元类改造为组合模式类。

2、代码敲敲

场景是不同部门都有对应的部门经理Manager,每个Manager都具有做针对性报告的能力report()。

该代码样例更多的体现了享元模式的外部状态,即通过传参方式动态定义需要共享的对象。

 

package structural.flyweight;

public class Manager implements Employee{

	private String titleString="部门经理";
	private String department;//部门
	private String reportContent;//报告内容
	
	public Manager(String department) {
		this.department=department;
	}
	@Override
	public void report() {
		System.out.println(reportContent);
	}
	public void setReportContent(String reportContent) {
		this.reportContent = reportContent;
	}
	
	
	

}
package structural.flyweight;

import java.util.HashMap;
import java.util.Map;

public class EmployeeFactory {
	private static final Map<String, Employee> EMPLOYEE_MAP=new HashMap<String, Employee>();
	public static Employee getManager(String department) {
		Manager manager=(Manager) EMPLOYEE_MAP.get(department);
		if (manager==null) {
			manager=new Manager(department);
			System.out.print("创建部门经理:"+department);
			String reportContent=department+"部门报告:此次报告的主要内容为...";
			manager.setReportContent(reportContent);
			System.out.print(" 创建报告:"+reportContent);
			EMPLOYEE_MAP.put(department, manager);
		}
		return manager;
	}
}
package structural.flyweight;

public class Test {
	private static final String departments[] = {"RD","QA","PM","BD"};
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			String department = departments[(int) (Math.random()*departments.length)];
			Manager manager=(Manager) EmployeeFactory.getManager(department);
			manager.report();
		}
	}
}

3、JDK中的源码应用

(1)Integer

Integer类中有一个内部类,实现了-128~127数字范围的对象初始化及共享,如果,是超出该范围则会重新new Integer,因为之前没有可共享的对象。

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int 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_VALUE
                    h = 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() {}
    }

其中,Integer的装箱过程,即由基本类型int得到Integer对象的过程,代码如下:

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

所以才会有这种结果:

4、总结

享元模式以共享的方式高效地支持大量细粒度对象的重用,享元对象能做到共享的关键是区分了内部状态(Intrinsic State)外部状态(Extrinsic State)。下面将对享元的内部状态和外部状态进行简单的介绍:

      (1)  内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享。如字符的内容,不会随外部环境的变化而变化,无论在任何环境下字符“a”始终是“a”,都不会变成“b”。

      (2)  外部状态是随环境改变而改变的、不可以共享的状态。享元对象的外部状态通常由客户端保存,并在享元对象被创建之后,需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态之间是相互独立的。如字符的颜色,可以在不同的地方有不同的颜色,例如有的“a”是红色的,有的“a”是绿色的,字符的大小也是如此,有的“a”是五号字,有的“a”是四号字。而且字符的颜色和大小是两个独立的外部状态,它们可以独立变化,相互之间没有影响,客户端可以在使用时将外部状态注入享元对象中。

      正因为区分了内部状态和外部状态,我们可以将具有相同内部状态的对象存储在享元池中,享元池中的对象是可以实现共享的,需要的时候就将对象从享元池中取出,实现对象的复用。通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份。

https://blog.csdn.net/LoveLion/article/details/7667781