享元模式(Flyweight)是设计模式中少数几个以提高系统性能为目的的模式之一。它的核心思想是:如果在一个系统中存在多个相同的对象,那么只需共享一份对象的拷贝,而不必为每一次使用都创建新的对象,这样可以节省重复创建对象的内存和时间开销。由于需要构造和维护这些可以共享的对象,因此,常常会出现一个工厂类,用于维护和创建对象。
享元模式分为内蕴状态和外蕴状态。内蕴状态就是共性,外蕴状态就是个性了。内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的;外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。在每个具体的环境下,客户端将外蕴状态传递给享元,从而创建不同的对象出来。
使用场景示例:有一个人事管理系统,假设公司甲,乙,丙共用这个系统,每个公司又有100个员工,每个公司员工都可以登录这个系统查询自己的收入情况,并且为了系统安全,每个公司都有自己独立的数据库,这种情况下,就可以使用享元模式为每个公司分别提供工资查询的接口,而一个公司下的所有员工可以共享一个查询(共享数据库连接)。
接下来,看具体实现代码。
/**
* @author pengl
* 2014-5-3
* 描述:享元接口
*/
public interface IReportManager {
public String createReport();
}
/**
*
* @author pengl
* 2014-5-3
* 描述:具体享元类一:创建财务报表
*/
public class FinancialReportManager implements IReportManager {
protected String companyId = null;
/**
* 外蕴状态 【个性】 在构造方法中给内蕴状态赋值
* @param companyId
*/
public FinancialReportManager(String companyId){
this.companyId = companyId;
}
/**
* 内蕴状态 【共性】
*/
public String createReport() {
return "This is a financial report from company " + companyId;
}
}
/**
* @author pengl
* 2014-5-3
* 描述:具体享元类二:创建员工报表
*/
public class EmployeeReportManager implements IReportManager{
protected String companyId = null;
/**
* 外蕴状态 【个性】 在构造方法中给内蕴状态赋值
* @param companyId
*/
public EmployeeReportManager(String companyId){
this.companyId = companyId;
}
/**
* 内蕴状态 【共性】
*/
public String createReport() {
return "This is a employee report from company " + companyId;
}
}
/**
* @author pengl
* 2014-5-3
* 描述:享元工厂类
*/
public class ReportManagerFactory {
private Map<String, IReportManager> financialReportManager =
new HashMap<String, IReportManager>();
private Map<String, IReportManager> employeeReportManager =
new HashMap<String, IReportManager>();
/**
* 根据公司ID获取公司财务报表
* @param companyId
* @return
*/
IReportManager getFinancialReportManager(String companyId){
IReportManager r = financialReportManager.get(companyId);
if(r==null){
r = new FinancialReportManager(companyId);
financialReportManager.put(companyId, r);
}
return r;
}
/**
* 根据公司ID获取公司员工报表
* @param companyId
* @return
*/
IReportManager getEmployeeReportManager(String companyId){
IReportManager r = employeeReportManager.get(companyId);
if(r==null){
r = new EmployeeReportManager(companyId);
employeeReportManager.put(companyId, r);
}
return r;
}
}
/**
* @author pengl
* 2014-5-3
* 描述:客户端调用
*/
public class Main {
public static void main(String[] args) {
ReportManagerFactory factory = new ReportManagerFactory();
IReportManager fReport = factory.getFinancialReportManager("A");
System.out.println(fReport.createReport());
IReportManager eReport = factory.getEmployeeReportManager("B");
System.out.println(eReport.createReport());
IReportManager fReport2 = factory.getFinancialReportManager("A");
System.out.println(fReport2.createReport());
IReportManager eReport2 = factory.getEmployeeReportManager("B");
System.out.println(eReport2.createReport());
System.out.println(fReport==fReport2);
System.out.println(eReport==eReport2);
}
}
控制台输出:
This is a financial report from company A
This is a employee report from company B
This is a financial report from company A
This is a employee report from company B
true
true
可以看出,同一个公司的调用是共用同一个对象。