享元模式定义:
运用共享技术来有效地支持大量细粒度对象的复用。它==通过共享已经存在的对象来大幅度减少需要创建的对象数量==、避免大量相似对象的开销,从而提高系统资源的利用率。
享元(Flyweight )模式中存在以下两种状态:
享元模式以共享的方式高效地支持大量细粒度对象的重用,能做到共享的关键就是区分了内部状态(Intrinsic State)和外部状态(Extrinsic State)。
享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。
正因为区分了内部状态和外部状态,我们可以将具有相同内部状态的对象存储在享元池中,享元池中的对象是可以实现共享的,需要的时候就将对象从享元池中取出,实现对象的复用。通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份。
享元模式结构较为复杂,一般结合工厂模式一起使用。主要有以下角色:
在享元模式中引入了享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
【例】俄罗斯方块
下面的图片是众所周知的俄罗斯方块中的一个个方块,这些方块有形状相同但颜色不一样的,如果在俄罗斯方块这个游戏中,每个不同或形状相同但颜色不一样的的方块都是一个实例对象,这些对象就要占用很多的内存空间,我们利用享元模式进行实现,将相同形状不同颜色的颜色看成是可变的外部状态。
享元类的设计是享元模式的要点之一,在享元类中要将内部状态和外部状态分开处理,通常将内部状态作为享元类的成员变量,而外部状态通过注入或形参的方式添加到享元类中。
俄罗斯方块有不同的形状,我们可以对这些形状向上抽取出AbstractBox抽象享元角色,用来定义共性的属性和行为。
public abstract class AbstractBox {
//获取图形
public abstract String getShape();
//显示图形及颜色,颜色在调用该方法时由外部参数传递
public void display(String color) {
System.out.println("方块形状:" + this.getShape() + " 颜色:" + color);
}
}
接下来就是定义不同的形状了,IBox类、LBox类、OBox类等,属于具体享元角色(根据情况可以使用单例模式)。
public class IBox extends AbstractBox {
@Override
public String getShape() {
return "I";
}
}
public class LBox extends AbstractBox {
@Override
public String getShape() {
return "L";
}
}
public class OBox extends AbstractBox {
@Override
public String getShape() {
return "O";
}
}
提供了一个工厂类(BoxFactory),用来管理享元对象(也就是AbstractBox子类对象),该工厂类对象只需要一个,所以可以使用单例模式。并给工厂类提供一个获取形状的方法。
public class BoxFactory {
//这个map是用来存储已经创建的具体图形对象,当你需要具体形状时可以从该对象中获取
private static HashMap<String, AbstractBox> map;
private BoxFactory() {
map = new HashMap<String, AbstractBox>();
AbstractBox iBox = new IBox();
AbstractBox lBox = new LBox();
AbstractBox oBox = new OBox();
map.put("I", iBox);
map.put("L", lBox);
map.put("O", oBox);
}
public static final BoxFactory getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final BoxFactory INSTANCE = new BoxFactory();
}
//根据图像名称获取对象
public AbstractBox getBox(String key) {
return map.get(key);
}
}
享元模式通常需要和其他模式一起联用,几种常见的联用方式如下:
(1)在享元模式的享元工厂类中通常提供一个静态的工厂方法用于返回享元对象,使用简单工厂模式来生成享元对象。
(2)在一个系统中,通常只有唯一一个享元工厂,因此可以使用单例模式进行享元工厂类的设计。
(3)享元模式可以结合组合模式形成复合享元模式,统一对多个享元对象设置外部状态。
在单纯享元模式中,所有的具体享元类都是可以共享的,不存在非共享具体享元类。
将一些单纯享元对象使用组合模式加以组合,还可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。
通过复合享元模式,可以确保复合享元类中所包含的每个单纯享元类都具有相同的外部状态,而这些单纯享元的内部状态往往可以不同。如果希望为多个内部状态不同的享元对象设置相同的外部状态,可以考虑使用复合享元模式。
当系统中存在大量相同或者相似的对象时,享元模式是一种较好的解决方案,它通过共享技术实现相同或相似的细粒度对象的复用,从而节约了内存空间,提高了系统性能。相比其他结构型设计模式,享元模式的使用频率并不算太高,但是作为一种以“节约内存,提高性能”为出发点的设计模式,它在软件开发中还是得到了一定程度的应用。
1,优点
2,缺点:
为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,使程序逻辑复杂
3,使用场景: