Flyweight(享元) 结构型 对象 1
Intent_意图2
运用共享技术有效地支持大量粒度的对象
Motivation_动机3
在有大量对象时,有可能会造成内存溢出,把其中共同的部分抽象出来,如果有相同的业务请求,直接返回内存中已有的对象
Applicability_适用性4
- 系统中有大量对内存消耗量大的、状态大部分可以外部化的对象
- 系统不依赖于这些对象身份,这些对象是不可分辨的
- 对象可以按照内蘊状态分为很多组,当把外蘊对象从对象中剔除时,每一组对象都可以用一个对象代替
Structure_结构5
Participants_参与者6
- Flyweight(抽象享元) 所有的具体享元类的基类,为具体享元规范需要实现的公共接口
- ConcreteFlyweight(具体享元) 实现抽象享元类所规范的接口
- UnsharedConcreteFlyweight(非共享享元) 不可共享的外部状态
- FlyweightFactory(享元工厂) 负责创建和管理享元角色
Collaborations_协作7
- Flyweight定义享元角色内部状态及外部状态的接口或实现
->intrinsic(内部状态):是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变。
->extrinsic(外部状态):外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态。 - ConcreteFlyweight实现Flyweight中定义的接口
->ConcreteFlyweight中的内部状态处理应与环境无关,不允许一个操作改变内部状态的同时,修改外部状态 - UnsharedConcreteFlyweight以参数形式注入到ConcreteFlyweight相关方法中
- FlyweightFactory创建管理Flyweight
->当客户请求一个享元对象时,FlyweightFactory检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在则创建一个新的享元对象
->通常情况下FlyweightFactory对象在整个系统中只有一个,使用单件
Comsequences_结果8
- 优点
大幅度减少对象的创建,降低系统的内存占用,提高效率
将许多“虚拟”对象的状态集中管理 - 缺点
提高系统复杂度,需要分离外部和内部状态,且外部状态具有固有化性质,不应该随着内部状态的变化而变化
一旦实现了享元模式,那么单个的逻辑实例将无法拥有独立而不同的行为 - 用途
系统有大量相似对象
需要缓冲池的场景
细粒度的对象具备较接近的外部状态,且内部状态与环境无关,也就是对象没有特定身份
Implementation/Sample Code_实现/范例代码910
Implementation
Flyweight
public abstract class Flyweight {
// 内部状态
private String intrinsic;
// 外部状态
protected final String Extrinsic;
// 要求享元角色必须接受外部状态
public Flyweight(String _Extrinsic) {
this.Extrinsic = _Extrinsic;
}
// 定义业务操作
public abstract void operate();
// 内部状态的getter/setter
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
ConcreteFlyweight
public class ConcreteFlyweight extends Flyweight {
// 接受外部状态
public ConcreteFlyweight(String _Extrinsic) {
super(_Extrinsic);
}
// 根据外部状态进行逻辑处理
public void operate() {
// TODO
}
}
FlyweightFactory
public class FlyweightFactory {
// 定义享元池
private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();
// 享元工厂
public static Flyweight getFlyweight(String extrinsic) {
// 需要返回的对象
Flyweight flyweight = null;
// 在池中没有该对象
if (pool.containsKey(extrinsic)) {
flyweight = pool.get(extrinsic);
} else {
// 根据外部状态创建享元对象
flyweight = new ConcreteFlyweight(extrinsic);
// 放置到池中
pool.put(Extrinsic, flyweight);
}
return flyweight;
}
}
Sample Code
Flyweight
public interface Tree {
void display();
void plant(int xCoord, int yCoord);
}
ConcreteFlyweight
public class Redwood implements Tree {
private int xCoord;
private int yCoord;
// xCoord, yCoord 共享
@Override
public void display() {
System.out.println("Plant a redwood in x" + xCoord + ", y" + yCoord);
}
// xCoord, yCoord 不共享
@Override
public void plant(int xCoord, int yCoord) {
this.xCoord = xCoord;
this.yCoord = yCoord;
}
}
FlyweightFactory
import java.util.HashMap;
import java.util.Random;
public class TreeFactory {
private static final HashMap<String, Tree> treeArray = new HashMap<>();
public Tree getRedwood() {
Tree redwood = treeArray.get("redwood");
if (redwood == null) {
redwood = new Redwood();
treeArray.put("redwood", redwood);
}
return redwood;
}
public static void displayTrees() {
Random rand = new Random();
for (Tree tree :
treeArray.values()) {
System.out.println(System.identityHashCode(tree)); // 打印对象地址
tree.plant(rand.nextInt(100), rand.nextInt(100)); // 设置对象xCoord, yCoord
tree.display();
}
}
}
Demo
public class Park {
public static void main(String[] args) {
TreeFactory treeFactory = new TreeFactory();
treeFactory.getRedwood(); // 初始化享元对象
treeFactory.displayTrees();
treeFactory.getRedwood(); // 引用享元对象
treeFactory.displayTrees();
}
}
Result
1163157884
Plant a redwood in x31, y46
1163157884
Plant a redwood in x41, y64
Known Uses_已知应用11
Java中的String类,String对象是Final类型,对象一旦创建就不可改变,在JAVA中字符串常量都存在常量池中,JAVA会确保一个字符串常量在常量池中只有一个拷贝。String a = “abc”,其中"abc"就是一个字符串常量。
Demo
public class Test {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
System.out.println(a == b);
}
}
Result
true
Related Patterns_相关模式12
- 单纯享元模式
单纯享元模式中的所有的具体享元类都是可以共享的,不存在非共享的具体享元类 - 复合享元模式
复合享元模式中的有些享元对象是由一些单纯享元对象组合而成,它们就是复合享元对象。虽然复合享元对象本身不能共享,但它们可以分解成单纯享元对象再被共享
复合享元类图:
模式分类归属 ↩︎
意图:描述该模式的作用,以及该模式的定义 ↩︎
动机:给出了问题以及如何解决这个问题的具体场景 ↩︎
适用性:描述模式可以被应用在什么场合 ↩︎
结构:提供了图示,显示出参与此模式的类之间的关系 ↩︎
参与者:描述在此设计中所涉及到的类和对象在模式中的责任和角色 ↩︎
协作 :告诉参与者如何在此模式中合作 ↩︎
结果:描述采用此模式之后可能产生的效果,好的与不好的 ↩︎
实现:提供了在实现该模式时需要使用的技巧,以及应该小心面对的问题 ↩︎
范例代码:提供代码的片段 ↩︎
已知应用:用来描述已经在真实系统中发现的模式例子 ↩︎
相关模式:描述了此模式和其他模式之间的关系 ↩︎