介绍
享元模式是对象的结构模式。享元模式以共享的方式高效地支持大量的细粒度对象。享元对象能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态可以共享,外蕴状态不可以共享。内蕴状态和外蕴状态相互独立。
模式实现
- 单纯享元模式
- 复合享元模式
单纯享元模式
单纯享元模式有以下角色:
- Flyweight(抽象享元),是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
- ConcreteFlyweight(具体享元),实现抽象享元角色中所规定的接口。
- Factory(享元工厂),负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
- Client(客户端),需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。
单纯享元模式结构图
(结构图来源于网上)
单纯享元模式实现
/**
* 抽象享元
*/
abstract public class Flyweight {
// 业务方法,参数state是外蕴状态(状态数据类型可以是其他,根据业务传入合适类型)
abstract public void operation(String state);
}
/**
* 具体享元
*/
public class ConcreteFlyweight extends Flyweight {
// 内蕴状态(状态数据类型可以是其他,根据业务传入合适类型)
private Character intrinsicState = null;
// 内蕴状态作为参量传入
public ConcreteFlyweight(Character state) {
this.intrinsicState = state;
}
// 外蕴状态作为参量传入方法中,改变方法的行为,但是并不改变对象的内蕴状态(状态数据类型可以是其他,根据业务传入合适类型)。
@Override
public void operation(String state) {
// 业务方法,根据实际业务编码
System.out.println("Intrinsic State = "
+ intrinsicState
+ ", Extrinsic State = "
+ state);
}
}
/**
* 享元工厂
*/
public class FlyweightFactory {
private final HashMap<Character, Flyweight> pool = new HashMap<>();
public FlyweightFactory() {
}
// 内蕴状态作为参量传入
public Flyweight factory(Character state) {
if (pool.containsKey(state)) {
return pool.get(state);
} else {
Flyweight fly = new ConcreteFlyweight(state);
pool.put(state, fly);
return fly;
}
}
}
/**
* 客户端
*/
public class FlyweightClient {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly = null;
fly = factory.factory(new Character('a'));
fly.operation("First Call");
fly = factory.factory(new Character('b'));
fly.operation("Second Call");
fly = factory.factory(new Character('c'));
fly.operation("Third Call");
}
}
复合享元模式
单纯享元模式有以下角色:
- Flyweight(抽象享元),是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
- ConcreteFlyweight(具体享元),实现抽象享元角色中所规定的接口。
- UnsharedFlyweight(复合享元),复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称做不可共享的享元对象。
- Factory(享元工厂),负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
- Client(客户端),需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。
复合享元模式结构图
(结构图来源于网上)
复合享元模式实现
/**
* 抽象享元
*/
abstract public class Flyweight {
// 业务方法,参数state是外蕴状态(状态数据类型可以是其他,根据业务传入合适类型)
abstract public void operation(String state);
}
/**
* 具体享元
*/
public class ConcreteFlyweight extends Flyweight {
// 内蕴状态(状态数据类型可以是其他,根据业务传入合适类型)
private Character intrinsicState = null;
// 内蕴状态作为参量传入
public ConcreteFlyweight(Character state) {
this.intrinsicState = state;
}
// 外蕴状态作为参量传入方法中,改变方法的行为,但是并不改变对象的内蕴状态(状态数据类型可以是其他,根据业务传入合适类型)。
@Override
public void operation(String state) {
// 业务方法,根据实际业务编码
System.out.println("Intrinsic State = "
+ intrinsicState
+ ", Extrinsic State = "
+ state);
}
}
/**
* 复合享元
*/
public class ConcreteCompositeFlyweight extends Flyweight {
private final HashMap<Character, Flyweight> flies = new HashMap<>();
public ConcreteCompositeFlyweight() {
}
public void add(Character key, Flyweight fly) {
flies.put(key, fly);
}
@Override
public void operation(String state) {
Flyweight flyweight = null;
Iterator<Map.Entry<Character, Flyweight>> iterator = flies.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Character, Flyweight> e = iterator.next();
flyweight = e.getValue();
flyweight.operation(state);
}
}
}
/**
1. 享元工厂
*/
public class FlyweightFactory {
private final HashMap<Character, Flyweight> flies = new HashMap<>();
public FlyweightFactory() {
}
// 单纯享元工厂方法,内蕴状态作为参量传入
public Flyweight factory(Character state) {
if (flies.containsKey(state)) {
return flies.get(state);
} else {
Flyweight fly = new ConcreteFlyweight(state);
flies.put(state, fly);
return fly;
}
}
// 复合享元工厂方法
public Flyweight factory(List<Character> compositeStates) {
ConcreteCompositeFlyweight compositeFlyweight = new ConcreteCompositeFlyweight();
for (int i = 0; i < compositeStates.size(); i++) {
Character state = compositeStates.get(i);
compositeFlyweight.add(state, factory(state));
}
return compositeFlyweight;
}
}
模式使用场景
- 一个系统有大量的对象。
- 这些对象耗费大量的内存。
- 这些对象的状态中的大部分可以外部化。
- 这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,没一个组都可以仅用一个对象代替。
- 软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
参考:
https://blog.csdn.net/justloveyou_/article/details/55045638
https://www.cnblogs.com/bastard/archive/2012/02/06/2340544.html
http://c.biancheng.net/view/1371.html