一、基本介绍
享元模式(结构型):运用共享技术来有効地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
二、包含角色
1.抽象享元角色:为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
2.具体享元角色:实现抽象享元角色中所规定的接口,为需要共享的对象。
3.非享元角色:不共享的外部状态,作为享元角色所需要的外部参数,以形参的方式传入。
4.享元工厂角色:负责创建和管理享元角色,一般用缓存管理这些对象。
三、案例及UML类图
案例说明:
验证码主要分为常见验证码,即数字+字母的形式,和计算类型验证码,即15+10=?类型的, 本公司主要提供验证码服务,其它要使用该服务的公司通过调用接口去创建使用该验证码, 因为访问量高,所以需要使用缓存来管理这些对象,节省内存开销。
UML类图:
类Captcha:
public interface Captcha {
/**
* 享元角色的公共接口
* @param captchaArgs 外部状态,即变化的部分,通过参数传递,可以为对象或其它的参数。
*/
void product(CaptchaArgs captchaArgs);
}
说明:验证码接口,抽象享元角色,定义验证码公共接口。
类ComputeCaptcha:
public class ComputeCaptcha implements Captcha {
@Override
public void product(CaptchaArgs captchaArgs) {
System.out.println("生成了一个宽度:"+captchaArgs.getWidth()+"," +
"高度:"+captchaArgs.getHeight()+"复杂度:"+captchaArgs.getComplexity()+"的计算型验证码。");
}
}
说明:计算型验证码类,具体享元角色,需要共享的类。
类NormalCaptcha:
public class NormalCaptcha implements Captcha {
@Override
public void product(CaptchaArgs captchaArgs) {
System.out.println("生成了一个宽度:"+captchaArgs.getWidth()+"," +
"高度:"+captchaArgs.getHeight()+"复杂度:"+captchaArgs.getComplexity()+"的常见验证码。");
}
}
说明:常见的验证码,如输入字母和数字的,具体享元角色,需要共享的类。
类CaptchaArgs:
public class CaptchaArgs {
public CaptchaArgs(Integer width, Integer height, String complexity) {
this.width = width;
this.height = height;
this.complexity = complexity;
}
private Integer width;
private Integer height;
/**
* 复杂度
*/
private String complexity;
public Integer getWidth() {
return width;
}
public void setWidth(Integer width) {
this.width = width;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
public String getComplexity() {
return complexity;
}
public void setComplexity(String complexity) {
this.complexity = complexity;
}
}
说明:验证码参数类,非享元角色,用于接收验证码的外部变化参数。
类FlyweightFactory:
public class FlyweightFactory {
/**
* 享元角色的缓存,key是验证码的类型,都是单例的
*/
private Map<Integer, Captcha> captchaMap = new ConcurrentHashMap<>();
/**
* 初始化时,先添加好其需要共享的享元角色
*/
public FlyweightFactory() {
//0表示正常验证码
captchaMap.put(0,new NormalCaptcha());
//1表示输入型验证码
captchaMap.put(1,new ComputeCaptcha());
}
/**
* 享元模式的获取,只返回缓存中的,做到共享。
* @param type 类型,0是正常验证码。1是计算型验证码
* @return 验证码类
*/
public Captcha getCaptcha(int type) {
if(captchaMap.keySet().contains(type)) {
return captchaMap.get(type);
}else {
return null;
}
}
}
说明:验证码工厂,享元工厂,用一个缓存保存需要共享的对象,为外部提供需要共享的变量。
类FlyweightTest:
public class FlyweightTest {
public static void main(String[] args) {
FlyweightFactory flyweightFactory = new FlyweightFactory();
//获取一个正常验证码
Captcha captcha = flyweightFactory.getCaptcha(0);
// 生成一个长宽为120且简单的正常验证码
captcha.product(new CaptchaArgs(120,120,"简单"));
//获取一个计算型验证码
captcha = flyweightFactory.getCaptcha(1);
// 生成一个长宽为200且复杂的计算型验证码
captcha.product(new CaptchaArgs(200,200,"复杂"));
}
}
说明:测试及客户端类。
四、适用场景
1.系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。
2.常见的缓存
五、其它
注意:由于享元模式需要额外维护一个保存享元的数据结构,所以应当在享元对象被使用得足够多时才值得使用享元模式。