享元模式(Flyweight Pattern)

定义:

     采用一个共享来避免大量拥有相同内容对象的开销。这种开销中最常见、直观的就是内存的损耗。享元模式以共享的方式高效的支持大量的细粒度对象。

     享元的英文是flyweight,是一个来自体育方面的专业用语,在拳击、摔跤和举重比赛中特指最轻量的级别。把这个单词移植到软件工程中,也是用来表示特别小的对象,即细粒度的对象。至于为什么把flyweight翻译为享元,可以理解为共享元对象,也就是共享细粒度对象。

      享元模式中区分了内蕴状态和外蕴状态。内蕴状态不能改变,是可以共享的。外蕴状态是可以的改变的,不能共享,由客户端保持。

模式组成:

  • Flyweight: 抽象享元类。所有具体享元类的超类或者接口,通过这个接口,Flyweight可以接受并作用于外部专题
  • ConcreteFlyweight: 具体享元类。指定内部状态,为内部状态增加存储空间
  • FlyweightFactory: 享元工厂类。用来创建并管理Flyweight对象,它主要用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)。


uml类图:


享元模式(Flyweight Pattern)

 

模式分类:

  • 单纯享元模式(即该对象没有外蕴状态,整个对象可以共享,类似于单例模式)
  • 复合享元模式(该对象有内蕴状态,也有外蕴状态,内蕴状态共享)

 

优点:

  • 极大的减少系统中对象的个数,节省内存的开销
  • 避免创建过多的对象,提升性能

 

缺点:(这也算缺点?有待考究)

  • 由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了
  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长


应用场景:

  • 存在大量重复对象的场景

在Java中,lang包下的Integer类,对于经常使用的-128 到 127 范围内的Integer对象当类一被加载时就被创建了,并保存在cache数组中,一旦程序调用valueOf 方法,如果i的值是在-128 到 127 之间就直接在cache缓存数组中去取Integer对象而不是创建一个新对象,这就是享元模式的应用。

 

      • java.lang.Integer#valueOf(int)
      • java.lang.Boolean#valueOf(boolean)
      • java.lang.Byte#valueOf(byte)
      • java.lang.Character#valueOf(char)

 


举个栗子:

 

定义抽象享元角色

abstract class Dish {
    public abstract void desc();
}

 

定义具体享元角色

class ButterMoshroom extends Dish {
    public String taste;

    public ButterMoshroom(String taste) {
        this.taste = taste;
    }

    @Override
    public void desc() {
        System.out.println(taste + "酱野山菌");
    }
}

定义工厂

class ButterMoshroomFactory {
    static Map<String, Dish> dishes = new HashMap<String, Dish>();

    public synchronized static Dish getDish(String taste) {
        Dish dish = dishes.get(taste);
        if (dish == null) {
            dish = new ButterMoshroom(taste);
        }
        dishes.put(taste, dish);
        return dish;
    }
}

客户端调用

public static void main(String[] args) {
        ButterMoshroomFactory.getDish("xo").desc();
        ButterMoshroomFactory.getDish("番茄").desc();
    }

输出

享元模式(Flyweight Pattern)