这是个很有意思的模式。它是通过共享技术来有效地支持大量细粒度对象的复用。
(1)Flyweight:描述一个接口,通过这个接口flyweight可以接受并作用于外部状态
(2)ConcreteFlyweight:实现Flyweight接口,并为内部状态增加存储空间。ConcreteFlyweight对象必须是共享的。它所存储的状态必须是内部的。
(3)FlyweightFactory:创建并管理Flyweight对象。确保合理地共享flyweight。当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个
(4)Client:维持一个对flyweight的引用。计算或存储一个flyweight的外部状态。
享元模式的特点有两个
(1)内在状态:用于创建对象。
(2)外在状态:外界传给实例的参数,用于实例执行某些方法。
如何理解享元模式?
刚开始看享元模式,这个模式感觉和单例模式很类似,两者区别是单例模式的关注点是创建单一对象,享元模式的关注点是规划创建对象。
享元模式不太好理解,它的难点在于理解它的结构以及为什么会创造出这样的设计结构。我从一本书上的享元模式的例子中理解了享元模式的目的以及实现。书中的例子是以“文档编辑器”加载数据为例:
通常上,文档编辑器上的文字或者字母,每个文字、字母都应该有一个存储
但是在物理结构上,却是相同的文字、字母共享同一个flyweight对象,从一个池中取数据,这种加载模式就是享元模式。
(1)减少对象的创建,降低系统的内存,使效率提高。
网上都说下面的是缺点,我并不这样认为,这是享元模式的特点。除了创建对象需要工厂外,内部外部状态也是其特点之一。
(1)享元模式需要区分出内部状态和外部状态,内部状态不可查看,外部状态是对象方法执行的参数,是客户赋予对象的,是可见的。外部状态在不同内部状态的对象下的方法中执行,可能产生不同的结果。
(1)一个应用程序使用了大量的对象
(2)完全由于使用大量的对象,造成很大的存储开销
(3)对象的大多数状态都可变为外部状态
(4)如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
(5)应用程序不依赖于对象标识,由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
模拟文档编辑器,写了一个简单的文字加载程序。如下:
定义加载字体的抽象方法
public abstract class Flyweight {
/**
* 加载字体
*
* @param fontAttribute
*/
abstract String load(FontAttribute fontAttribute);
}
定义文字的属性
@Data
public class FontAttribute {
/**
* 字体颜色:30黑 31红 32绿 33黄 34蓝 35紫 36深绿 37白
*/
private Integer color;
/**
* 字体格式:0重置 1加粗 2减弱 3斜体 4下划线 5慢速闪烁 6快速闪烁
*/
private Integer fontType;
}
定义加载字体的实现方法,以及文字标志量
public class Font extends Flyweight {
//文字为内在属性
private String word;
public Font(String word) {
this.word = word;
}
/**
* 加载字体,FontAttribute为外在属性
*
* @param fontAttribute
*/
@Override
public String load(FontAttribute fontAttribute) {
//格式化字体属性
return String.format("\033[%d;%dm%s\033[0m",fontAttribute.getColor(),fontAttribute.getFontType(),this.word);
}
}
定义创建文字的方法
public class FontFactory {
HashMap<String, Font> fontHashMap = new HashMap<>();
/**
* 造字
*
* @param word
* @return
*/
public Font createFont(String word) {
//如果map中有该文字,则直接获取,不需要创建
if (fontHashMap.containsKey(word)) {
return fontHashMap.get(word);
}
//若map中不存在该文字,则造字
return new Font(word);
}
}
定义调用方法
public class Client {
public static void main(String[] args) {
FontFactory factory = new FontFactory();
//文字
String[] words = {"h", "e", "l", "l", "o", "w", "o", "r", "l", "d"};
//颜色编码
Integer[] colors = {30, 31, 32, 33, 34, 35, 36, 37};
//字体格式
Integer[] fontTypes = {0, 1, 2, 3, 4, 5, 6, 7};
for (int i = 0; i < words.length; i++) {
Font font = factory.createFont(words[i]);
FontAttribute attribute = new FontAttribute();
//设置字体属性
attribute.setColor(colors[i % colors.length]);
attribute.setFontType(fontTypes[i % fontTypes.length]);
//打印文字
System.out.print(font.load(attribute));
}
}
}
效果: