享元模式
享元模式(Flyweight Pattern)是池技术的重要实现方式,其定义如下:Use sharing to
support large numbers of fine-grained objects efficiently.(使用共享对象可有效地支持大量的细
粒度的对象。)
享元模式的定义为我们提出了两个要求:细粒度的对象和共享对象。我们知道分配太多
的对象到应用程序中将有损程序的性能,同时还容易造成内存溢出,那怎么避免呢?就是享
元模式提到的共享技术。我们先来了解一下对象的内部状态和外部状态。
要求细粒度对象,那么不可避免地使得对象数量多且性质相近,那我们就将这些对象的
信息分为两个部分:内部状态(intrinsic)与外部状态(extrinsic)。
● 内部状态
内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变,
如我们例子中的id、postAddress等,它们可以作为一个对象的动态附加信息,不必直接储存
在具体某个对象中,属于可以共享的部分。
● 外部状态
外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态,如
我们例子中的考试科目+考试地点复合字符串,它是一批对象的统一标识,是唯一的一个索
引值。
● 内存泄漏
无意识的代码缺陷,导致内存泄漏,JVM不能获得连续的内存空间。
● 对象太多
代码写得很烂,产生的对象太多,内存被耗尽。现在的情况是没有内存泄漏,那只有一
种原因——代码太差把内存耗尽。
● 考试科目,选择框。
● 考试地点,选择框,根据科目不同,列表不同。
● 准考证邮寄地址,输入框。
还有其他一堆信息,我们以这三者作为代表来讲解。信息填写完毕后,点击确认,报名
就结束了。简单程序的业务逻辑也确实是这样,为什么出现Crash情况呢?那肯定是和压力
有关系!
我们先把这个过程的静态类图画出来,如图
很简单的工厂方法模式,表现层通过工厂方法模式创建对象,然后传递给业务层和持久
层,最终保存到数据库中,为什么要使用工厂方法模式而不用直接new一个对象呢?因为是
在框架下编程,必须有一个对象工厂(ObjectFactory,Spring也有对象工厂)。
package FlyweightP; public class SignInfo { //报名人员的ID private String id; //考试地点 private String location; //考试科目 private String subject; //邮寄地址 private String postAddress; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getPostAddress() { return postAddress; } public void setPostAddress(String postAddress) { this.postAddress = postAddress; } }
package FlyweightP; public class SignInfoFactory { public static SignInfo getSignInfo(){ return new SignInfo(); } }
package FlyweightP; public class Client { public static void main(String[] args) { SignInfo signInfo = SignInfoFactory.getSignInfo(); } }
我们自己来设计一个共
享对象池,需要实现如下两个功能。
● 容器定义
我们要定义一个池容器,在这个容器中容纳哪些对象。
● 提供客户端访问的接口
我们要提供一个接口供客户端访问,池中有可用对象时,可以直接从池中获得,否则建
立一个新的对象,并放置到池中。
package FlyweightP; public class SignInfoPool extends SignInfo { //定义一个对象池提取的key值 private String key; public SignInfoPool(String key){ this.key = key; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } }
package FlyweightP; public class Client { public static void main(String[] args) { // SignInfo signInfo = SignInfoFactory.getSignInfo(); //初始化对象池 for(int i=0;i<4;i++){ String subject = "科目" + i; //初始化地址 for(int j=0;j<30;j++){ String key = subject + "考试地点"+j; SignInfoFactory.getSignInfo(key); } } SignInfo signInfo = SignInfoFactory.getSignInfo("科目1考试地点1"); } }