享元模式
定义
运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
简单来说就是将大量的小的重复使用的对象统一管理起来,避免用户多次创建重复对象造成的资源浪费;
示例
享元接口
public interface MyFlyWeight {
public void operation();
}
享元实现类
public class MyFlyWeightImpl implements MyFlyWeight {
private String state;
public MyFlyWeightImpl(String state) {
this.state = state;
}
@Override
public void operation() {
System.out.println("对象:"+this);
}
}
享元工厂,保证每次传入相同状态只返回相同的对象;
public class FlyWeightFactory {
private static final HashMap<String, MyFlyWeight> flyWeights = new HashMap<String, MyFlyWeight>();
public static MyFlyWeight getFlyWeight(String state){
MyFlyWeight myFlyWeight = flyWeights.get(state);
if(myFlyWeight == null){
myFlyWeight = new MyFlyWeightImpl(state);
flyWeights.put(state, myFlyWeight);
}
return myFlyWeight;
}
public static int getSize(){
return flyWeights.size();
}
}
测试类
public class MyFlyWeightTest {
public static void main(String[] args) {
MyFlyWeight flyWeight = null;
System.out.println("first request");
flyWeight = FlyWeightFactory.getFlyWeight("a");
flyWeight.operation();
System.out.println("对象池数量:"+FlyWeightFactory.getSize());
System.out.println("second request");
flyWeight = FlyWeightFactory.getFlyWeight("b");
flyWeight.operation();
System.out.println("对象池数量:"+FlyWeightFactory.getSize());
System.out.println("third request");
flyWeight = FlyWeightFactory.getFlyWeight("a");
flyWeight.operation();
System.out.println("对象池数量:"+FlyWeightFactory.getSize());
}
}
结果:三次请求有两次相同状态,因此实际上只有2个对象保存,请求相同状态a返回相同的对象
first request
对象:com.huzd.study.flyweight.MyFlyWeightImpl@4a5ab2
对象池数量:1
second request
对象:com.huzd.study.flyweight.MyFlyWeightImpl@1888759
对象池数量:2
third request
对象:com.huzd.study.flyweight.MyFlyWeightImpl@4a5ab2
对象池数量:2
分析
- 为了减少不会要额内存消耗,将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗。
与单例对比
- 享元模式是共享,但共享的是池,而不是单一,当然这个池的大小可以是1个。享元模式的目的是共享,避免多次创建耗费资源,单例模式的目的是限制创建多个对象以避免冲突等,所以即使都是一个对象,目的也不同。
- 如上面的例子中享元模式虽然每次相同状态返回同一个对象,但实际上不同状态还是会有不同对象返回,对象池中也会有多个对象存在,但是单例只允许一个对象存在;
应用
在JAVA语言中,String类型就是使用了享元模式。String对象是final类型,对象一旦创建就不可改变。在JAVA中字符串常量都是存在常量池中的,这个字符串常量池在jdk 6.0以前是位于常量池中,位于永久代,而在JDK 7.0中,JVM将其从永久代拿出来放置于堆中。JAVA会确保一个字符串常量在常量池中只有一个拷贝。String a=“abc”,其中"abc"就是一个字符串常量。
String s1 = "abc";
String s2 = "abc";
如果我们以s1==s2进行比较的话所得结果为:true,因为s1和s2保存的是字符串常量池中的同一个字符串地址。这就类似于我们今天所讲述的享元模式,字符串一旦定义之后就可以被共享使用,因为他们是不可改变的,同时被多处调用也不会存在任何隐患。