一、使用场景
在程序设计过程中,有时需要创建大量或相似的对象实例,创建这么多的对象将耗费更多的系统资源。需要将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,从而降低内存的消耗。
二、享元模式
运用共享技术来有效地支持大量细度对象的复用。通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似对象的开销,从而提高系统资源的利用率。
享元模式存在两种状态:
1)内部状态,不会随着环境改变而改变的可共享部分;
2)外部状态,随环境改变而改变的不可共享部分;
享元模式一般结合工厂模式一起使用,主要角色有:
1)抽象享元角色,通常是一个接口或抽象类,声明享元类公共的方法,这些方法可向外界提供享元对象的内部结构,同时也可以通过这些方法设置外部状态;
2)具体享元,为内部状态提供存储空间,通常可以结合单例模式来设计具体享元类,为每个具体享元提供唯一的享元对象;
3)享元工厂,负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
图 享元模式UML图
需求描述:某出租车公司名下有多辆出租车,公司需要统计每辆车每天的总里程、及乘客数量。
public class FlyweightTest {
static abstract class Taxi {
protected int id; //汽车编号
protected int mileage; //总里程
protected int passengerNum; //乘客数量
/**
* 载客
* @param num 乘客数量
* @param mileage 里程
*/
public abstract void carryPassenger(int num, int mileage);
}
static class RealTaxi extends Taxi {
public RealTaxi(Integer id) {
this.id = id;
}
@Override
public void carryPassenger(int num, int mileage) {
this.passengerNum += num;
this.mileage += mileage;
}
@Override
public String toString() {
return "RealTaxi{" +
"id=" + id +
", mileage=" + mileage +
", passengerNum=" + passengerNum +
'}';
}
}
static class TaxiFactory {
private TaxiFactory() {}
private static Map<Integer,Taxi> taxiMap = new HashMap<>();
/**
* 派车
* @param id 汽车编号
* @return 出租车
*/
public static Taxi sendCar(Integer id) {
Taxi taxi = taxiMap.get(id);
if (taxi == null) {
taxi = new RealTaxi(id);
taxiMap.put(id,taxi);
}
return taxi;
}
/**
* 数据统计
*/
public static void statistics() {
Set<Integer> keySet = taxiMap.keySet();
Iterator<Integer> iterator = keySet.iterator();
while (iterator.hasNext()) {
Integer id = iterator.next();
Taxi taxi = taxiMap.get(id);
System.out.println(taxi);
}
}
}
public static void main(String[] args) {
Random random = new Random(12);
for (int i = 0; i < 24; i++) {
Taxi taxi = TaxiFactory.sendCar(random.nextInt(5));//总共5辆车,编号从0到4
taxi.carryPassenger(random.nextInt(3) + 1, random.nextInt(10));//载客
}
TaxiFactory.statistics();
}
// 运行结果:
// RealTaxi{id=0, mileage=14, passengerNum=14}
// RealTaxi{id=1, mileage=33, passengerNum=14}
// RealTaxi{id=2, mileage=14, passengerNum=3}
// RealTaxi{id=3, mileage=24, passengerNum=9}
// RealTaxi{id=4, mileage=15, passengerNum=10}
}
2.1 优缺点
优点:1)极大减少内存中相同或相似对象的数量,节约系统资源;2)享元模式中外部状态相对独立,且不影响内部状态;
缺点:享元对象分为内部状态和外部状态,使程序逻辑变得复杂;