- 这是个很有意思的模式。它是通过共享技术来有效地支持大量细粒度对象的复用。
-
- (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));
- }
- }
- }
-
效果: