定义
运用共享技术有效地支持大量细粒度的对象。
结构和说明
示例代码
public class FlyweightDemo {
/**
* 享元接口,通过这个接口享元可以接受并作用于外部状态
*/
public static interface Flyweight {
/**
* 示例操作,传入外部状态
*
* @param extrinsicState
* 示例参数,外部状态
*/
void operation(String extrinsicState);
}
/**
* 享元对象
*/
public static class ConcreteFlyweight implements Flyweight {
/**
* 示例,描述内部状态
*/
private String intrinsicState;
public ConcreteFlyweight(String state) {
this.intrinsicState = state;
}
@Override
public void operation(String extrinsicState) {
// 具体的功能处理,可能会用到享元内部、外部的状态
}
}
/**
* 不需要共享的 Flyweight 对象
*
* 通常是将被共享的享元对象作为子节点组合出来的对象
*/
public static class UnsharedConcreteFlyweight implements Flyweight {
/**
* 示例,描述对象的状态
*/
private String allState;
@Override
public void operation(String extrinsicState) {
// 具体的功能处理
}
}
/**
* 享元工厂
*/
public static class FlyweightFactory {
/**
* 缓存多个 Flyweight 对象,这里这是示意一下
*/
private Map<String, Flyweight> fsMap = new HashMap<>();
/**
* 获取 key 对应的享元对象
*
* @param key
* 获取享元对象的 key, 只是示意
* @return key 对应的享元对象
*/
public Flyweight getFlyweight(String key) {
// 这个方法中基本实现步骤如下:
// 1: 先从缓存中找,是否存在 key 对应的 Flyweight 对象
Flyweight f = fsMap.get(key);
// 2:如果存在就返回相应的 Flyweight 对象
if (f == null) {
// 3:如果不存在
// 3.1: 创建一个新的 Flyweight 对象
f = new ConcreteFlyweight(key);
// 3.2: 把这个新的 Flyweight 对象添加到缓存中
fsMap.put(key, f);
// 3.3: 然后返回这个新的 Flyweight 对象
}
return f;
}
}
/**
* Client 对象,通常会维护一个对 Flyweight 的引用, 计算或存储一个或多个 Flyweight 的外部状态
*/
public static class Client {
// 具体的功能处理
}
}
调用顺序
享元模式的使用上,有两种情况,一种是没有“不需要共享”的享元对象,就如同前面的示例那样,只有共享享元对象的情况;还有一种既有共享享元对象,又有不需要共享的享元对象的情况。
只有共享享元对象的情况下
优缺点
优点
- 减少对象数量,节省内存空间。
缺点
- 维护共享对象,需要额外开销。
思考
本质
分离和共享。
何时选用
- 如果一个应用程序使用了大量的细粒度对象,可以使用享元模式来减少对象数量。
- 如果由于使用大量的对象,造成很大的存储开销,可以使用享元模式来减少对象数量,并节约内存。
- 如果对象的大多数状态都可以转变为外部状态,比如通过计算得到,或者是从外部传入等,可以使用享元模式来实现内部状态和外部状态的分离。
- 如果不考虑对象的外部状态,可以使用相对较少的共享对象取代很多组合对象,可以使用享元模式来共享对象,然后组合对象来使用这些共享对象。
相关模式
- 享元模式与单例模式
这两个模式可以组合使用。
通常情况下,享元模式中的享元工厂可以实现成为单例。另外,享元工厂中缓存的享元对象,都是单实例的,可以看成是单例模式的一种变形控制,在享元工厂中来单例享元对象。
- 享元模式与组合模式
这两个模式可以组合使用。
在享元模式中,存在不需要共享的享元实现,这些不需要共享的享元通常是对共享的享元对象的组合对象。也就是说,享元模式通常会和组合模式使用,来实现更复杂的对象层次结构。
- 享元模式和状态模式
这两个模式可以组合使用。
可以使用享元模式来共享状态模式中的状态对象。通常在状态模式中,会存在数量很大,细粒度的状态对象,而且他们基本上是可以重复使用的,都是用来处理某一个固定的状态的,它们需要的数据通常都是由上下文传入,也就是变化部分都分离出去了,所以可以用享元模式来实现这些状态对象。
- 享元模式与策略模式
这两个模式剋组合使用。
可以使用享元模式来实现策略模式中的策略对象。和状态模式一样,在策略模式中也存在大量细粒度的策略对象,它们需要的数据同样是从上下文传入的,所以可以使用享元模式来实现这些策略对象。