享元模式的英文原文是:Use share to support large number of fine-grained objects efficiently.意思是:使用共享对象可以有效的支持大量的细粒度的对象。这里的共享对象指的是对象常驻内存,都可以使用;细粒度对象指的是,对象的很多属性相似或相同,可以提取出公共属性。享元对象能够做到共享的关键就是区分内部状态和外部状态,上边提到的公共属性就是内部状态,不同的属性是外部状态。再看看内部状态和外部状态的的定义:
内部状态:存储在享元对象的内部,可以共享的信息,并且不会随环境的改变而改变。
外部状态:随外部环境改变而改变且不可共享的状态,外部状态由客户端保存,在必要的时候再将其传入到享元对象内部。
享元模式的四种角色:
抽象享元角色(Flyweight):对享元类进行抽象规定了必须要实现的公共接口,需要外部状态(External State)的操作可以通过方法的参数传入。
具体享元角色(ConcreteFlyweight):实现抽象享元角色定义的业务,具体享元对象的内部状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。
复合享元角色(UnsharableFlyweight):复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个具体享元角色的组合。
享元工厂(FlyweightFactory):该角色构造一个池容器,负责创建和管理享元角色,并提供从容器池中获取对象的方法,保证享元对象可以被系统适当的共享。
享元模式的类图:
各类对应的实现代码:
抽象享元角色:
package com.zz.flyweight;
/**
* 抽象享元角色(Flyweight)
* Copyright 2015年5月13日
* created by txxs
* all right reserved
*/
public abstract class Flyweight {
//内部状态
private String intrinsic;
//外部状态
private String Extrinsic;
//定义业务操作
public abstract void operate();
//要求享元角色必须接受外部状态
public Flyweight(String Extrinsic){
this.Extrinsic = Extrinsic;
}
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
具体享元角色:
package com.zz.flyweight;
/**
* 具体享元角色
* Copyright 2015年5月13日
* created by txxs
* all right reserved
*/
public class ConcreteFlyweight extends Flyweight {
//接受外部状态
public ConcreteFlyweight(String Extrinsic) {
super(Extrinsic);
}
@Override
public void operate() {
//业务处理
}
}
复合享元角色:
package com.zz.flyweight;
/**
* 复合享元角色
* Copyright 2015年5月13日
* created by txxs
* all right reserved
*/
public class UnsharedConcreteFlyweight extends Flyweight {
//接受外部状态
public UnsharedConcreteFlyweight(String Extrinsic) {
super(Extrinsic);
}
@Override
public void operate() {
//业务逻辑
}
}
享元工厂:
package com.zz.flyweight;
import java.util.HashMap;
/**
* 享元工厂
* Copyright 2015年5月13日
* created by txxs
* all right reserved
*/
public class FlyweightFactory {
//定义一个池容器
private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();
//享元工厂
public static Flyweight getFlyweight(String extrinsic){
//需要返回的对象
Flyweight flyweight = null;
//获取返回的对象
if(pool.containsKey(extrinsic)){
flyweight = pool.get(extrinsic);
}else{
flyweight = new ConcreteFlyweight(extrinsic);
pool.put(extrinsic, flyweight);
}
return flyweight;
}
}
享元模式的优缺点:
大幅降低内存中对象的数量,降低内存的占有,提高性能。但是增加了系统的复杂性,需要分离出外部状态和内部状态,内部状态具有固化的特性,不应该随外部状态的改变而改变,使得逻辑复杂化;并且享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
享元模式适合的场合:
1、系统中有大量的相似的对象,这些对象耗费大量的内存
2、需要缓冲池的场景
比如java的基础类库中就大量使用了享元模式,String、Integer等类都利用享元模式提供了内部的池化机制,看下面的代码:
package com.zz.decorator.impl;
/**
* 测试类
* Copyright 2015年4月20日
* created by txxs
* all right reserved
*/
public class ClientTest {
public static void main(String args[]){
String a = "abc";
String b = "abc";
System.out.println(a==b);
System.out.println("----------------------");
String c=new String("Hello");
String d=new String("Hello");
System.out.println(c==d);
}
}
第一个输出的就是true,第二个输出的fasle。