概念
所谓享元模式就是运行共享技术有效地支持大量细粒度对象的复用。
目的
节省内存,对象复用。在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
使用场景
1、系统有大量相似对象。 2、需要缓冲池的场景。
个人理解
享元设计模式 = 工厂模式 + 单例模式
业务实践
个人案例
APP应用信息。比如极光推送,必须先在其开放平台注册一个APP应用,注册成功后,你将获取到一个AppId和AppSecret以及一个APP应用的英文名称。当需要对应用A进行消息推送的时候,需要构造一个极光推送的客户端对象,构造推送的设备信息以及推送的消息。当你只有一个APP应用,我们理所当然地使用单例设计模式即可解决API的调用问题,可是拥有多个APP应用的时候呢,传统思维是根据推送的设备信息,查询所属的APP应用,然后调用其API。其实这个时候,我们可以利用享元设计模式使得代码更加优雅。
代码如下
public class AppInfoFactory {
private static final ConcurrentHashMap<String, AppInfo> appInfoMap = new ConcurrentHashMap<>();
/**
* 享元设计模式 = 工厂模式 + 单例模式
* 基于享元设计模式减少内存使用,复用对象
* @param appName APP的名称唯一
* @return APP对象实体
*/
public static AppInfo getAppInfo(String appName) {
Assert.state(appName != null, "应用名称不能为空!");
AppInfo appInfo = appInfoMap.get(appName);
if (appInfo == null) {
IAppInfoService appInfoService = ApplicationSupport.getBean(IAppInfoService.class);
appInfo = appInfoService.selectOne(new EntityWrapper<AppInfo>().eq("app_name", appName));
Assert.state(appInfo != null, "未找到名称为"+appName+"对应的APP的信息!");
appInfoMap.put(appName,appInfo);
}
return appInfo;
}
/**
* 添加|修改一个APP后,加入内存中进行复用
* @param appInfo
*/
public static void updateAppInfo(AppInfo appInfo){
Assert.state(appInfo != null, "应用不能为空!");
Assert.state(appInfo.getAppName() != null, "应用名称不能为空!");
appInfoMap.put(appInfo.getAppName(),appInfo);
}
}
工具类
/**
* 获取Spring容器管理的Bean对象,应用中配置参数
**/
@Component
public class ApplicationSupport implements DisposableBean, ApplicationContextAware {
private static ApplicationContext applicationContext;
// 获取配置文件参数值
public static String getParamVal(String paramKey){
return applicationContext.getEnvironment().getProperty(paramKey);
}
// 获取bean对象
public static Object getBean(String name) {
Assert.hasText(name);
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void destroy() throws Exception {
applicationContext = null;
}
}
注意事项
不同于网上其他的享元模式的代码案例,此处,我做了很多的变更,但其目的仍然是对于对象的复用,内存的减少。
当在内存中查询没有发现需要的对象时,将从数据库查询,这样提高了拓展性。
因为存在新添加的APP信息,当程序在运行时,注册了一个新的客户端,那么内存中却并没有这个信息,那么我们将从数据库中查询,类似于缓存中没有,从数据库中查询。当存在管理页面,注册了一个APP应用后,实施人员添加到后端数据库表中时,可以调用静态方法updateAppInfo,添加到内存中。
网友评论