定义:享元模式(英语:Flyweight Pattern)是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
由定义我们可以知道几点:
1. 享元模式是用来共享相似的物件,从而达到减少内存使用量的一个目的。
2. 常见的作法是把要共享的状态存放在数据结构中,需要使用时再从数据结构中提取使用。
3. 适用于大量物件重复调用,浪费内存消耗。
先来看看代码实现吧,这里我举个工厂的例子。一个工厂的运作需要若干个工人,如果每个工人都去new一个的话,工厂稍微大一点都会造成内存崩溃,所以这时用享元模式再好不过。
首先是工人基类。
package test;
public abstract class Worker {
public final String name;
public Worker() {
this.name = getName();
}
public abstract String getName();
public abstract void work();
}
然后是两种工种(装箱工人与拆箱工人)
package test;
public class LoadWorker extends Worker {
@Override
public String getName() {
return "装箱工人";
}
public void work() {
System.out.println("开始装箱了");
}
}
package test;
public class UnboxWorker extends Worker {
@Override
public String getName() {
return "拆箱工人";
}
public void work() {
System.out.println("开始拆箱了");
}
}
最后是最关键的,工厂类,是享元模式的核心实现类。
package test;
import java.util.HashMap;
public class WorkerFactory {
public static WorkerFactory instance = new WorkerFactory();
private WorkerFactory() {
}
public static WorkerFactory getInstance() {
return instance;
}
public static HashMap<String, Worker> workers = new HashMap<String, Worker>();
public static Worker getWorker(String name) {
Worker worker = null;
if(name.equals("装箱工人")) {
worker = workers.get("装箱工人");
if(worker == null) {
worker = new LoadWorker();
workers.put("装箱工人", worker);
}
} else if(name.equals("拆箱工人")) {
worker = workers.get("拆箱工人");
if(worker == null) {
worker = new UnboxWorker();
workers.put("拆箱工人", worker);
}
}
return worker;
}
}
这里工厂类做成单例模式,工人用一个hashmap来存放。
接下来测试一下吧。
package test;
public class testT {
@SuppressWarnings("static-access")
public static void main(String[] args) {
System.out.println("工厂开始工作了,工厂运作需要3个拆箱工人与5个装箱工人");
Worker worker1 = WorkerFactory.getInstance().getWorker("拆箱工人");
Worker worker2 = WorkerFactory.getInstance().getWorker("拆箱工人");
Worker worker3 = WorkerFactory.getInstance().getWorker("拆箱工人");
Worker worker4 = WorkerFactory.getInstance().getWorker("装箱工人");
Worker worker5 = WorkerFactory.getInstance().getWorker("装箱工人");
Worker worker6 = WorkerFactory.getInstance().getWorker("装箱工人");
Worker worker7 = WorkerFactory.getInstance().getWorker("装箱工人");
Worker worker8 = WorkerFactory.getInstance().getWorker("装箱工人");
worker1.work();
worker2.work();
worker3.work();
worker4.work();
worker5.work();
worker6.work();
worker7.work();
worker8.work();
System.out.println("---------------------");
System.out.println(worker1 == worker2);
System.out.println(worker4 == worker5);
}
}
控制台打印
可以看到,该实现的功能都依然可以实现,我这里最后加了一个对象判断,用来验证是否为同一个对象。
从打印的结果上来看,我们的3个拆箱工人都属于同一个对象,5个装箱工人也都属于同一个对象,这样8个工人只需要new两个对象即可完成一个工厂的流程,极大减少了内存的浪费。
其实类似String也用到了享元模式,如下所示
package test;
public class testT {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
System.out.println(a == b);
}
}
这里在实例化一个字符串"abc"时,String类就把abc暂时存放在一个数据结构,当实例化b的时候发现abc已经存在,就直接拿出来用了,所以这个时候a和b也都是同一个对象。
包括一些线程池,数据库连接池也都是基于享元模式的思想。