1.核心思想
适用于需要创建大量相似对象的情况,核心思想是共享对象,以减少系统中对象的数量,从而节省内存和提高性能。
个人理解:通过内部状态减少对象的创建,通过外部状态增加对象多元化
2.组成
享元接口:这是一个接口或者抽象类,定义了具体享元对象的外部状态(extrinsic state)可以操作的行为
具体享元(Concrete Flyweight):实现了享元接口,包含并共享具体的内部状态(intrinsic state)。具体享元对象必须是可共享的,任何其余状态都必须由外部环境提供。
享元工厂(Flyweight Factory):负责创建和管理享元对象。它确保享元对象被正确地共享和重用。通常在请求时,如果存在对应的享元对象,则返回已有的实例;如果不存在,则创建一个新的实例
客户端(Client):使用享元模式的对象。它维护对享元对象的引用,并在需要时向享元工厂请求享元对象的实例。客户端可以传递外部状态给享元对象,以便定制享元对象的行为。
非共享具体享元(Unshared Concrete Flyweight):并非所有的享元对象都可以被共享。这些非共享的享元对象通常会因为内部状态不能被外部对象引用或者其他原因不能被共享。(可忽略)
3.代码实现
3.1 享元接口
/**
* 享元模式
* @todo 享元接口
*/
public interface TxtEdit {
void printTxt(int position);
}
3.2 具体享元
//具体享元
public class ConcreteTxtEdit implements TxtEdit{
//内部状态
private char charValue;
//外部状态
private int position;
public ConcreteTxtEdit(char charValue){
this.charValue = charValue;
}
@Override
public void printTxt(int position) {
//打印字符和位置信息
System.out.println("charValue = " + charValue + ", position = " + position);
}
}
3.3 享元工厂
public class TxtEditFactory {
private Map<Character, ConcreteTxtEdit> txtEdits = new HashMap<>();
public TxtEdit getTxtEdit(char charValue) {
ConcreteTxtEdit concreteTxtEdit = txtEdits.get(charValue);
if (concreteTxtEdit == null) {
System.out.println("对象不存在,字符是"+charValue);
concreteTxtEdit = new ConcreteTxtEdit(charValue);
txtEdits.put(charValue,concreteTxtEdit);
}else {
System.out.println("对象存在,字符是"+charValue);
}
return concreteTxtEdit;
}
}
3.4 客户端
// Client.java - 客户端代码
public class Client {
public static void main(String[] args) {
TxtEditFactory factory = new TxtEditFactory();
// 创建文本
String text = "Hello, World!";
// 处理文本
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
TxtEdit txtEdit = factory.getTxtEdit(c);
txtEdit.printTxt(i);
}
}
}
4.源码
Integer.valueof(127)和Integer.valueof(128)是一个典型的列子:内部是通过享元模式定义了一个静态的Integer的数组,当在-128-127是使用相同的对象,不在这个范围才会新建。
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() {}
}