flyweight是“轻量级”的意思,指的是拳击比赛中选手体重最轻的等级。顾名思义,该设计模式的作用是为了让对象变“轻”。对象在计算机中是虚拟存在的东西,“重”和“轻”并非指实际重量,而是它们“所使用的内存大小”。使用内存多的读写就是“重”对象,使用内存少的对象就是“轻”对象。
为了能够在计算机中保存对象,需要分配给其足够的内存空间。当程序中需要大量对象时,如果都使用new关键字来分配内存,将会消耗大量内存空间。flyweight模式就可以通过尽量共享实例来避免new出实例。
例如下图可以共用一个Hello world对象,其中字符串“Hello world”为内部状态,可共享;字体颜色为外部状态,不可共享,由客户端设定。
image.png 在享元模式中可以共享的相同内容称为内部状态,而哪些需要外部环境来设置的不能共享的内容称为外部状态,其中外部状态和内部状态是相互独立的。外部状态的变化不会引起内部状态的变化。由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有一些不同的特征,而相同的内部状态是可以共享的。也就是说,享元模式的本质是分离与共享:分离变与不变,并且共享不变。把一个对象的状态分为内部状态和外部状态,内部状态是不变的,外部状态是变化的;可以通过共享不变的部分,达到减少对象数量并节约内存的目的。
在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(用于储存相同内部状态的享元对象)。在实际使用中,能够共享的内部状态是有限的额,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也称为细粒度对象。享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。

角色:

Flyweight:

享元接口,通过这个接口传入外部状态并作用与外部状态;

  1. public interface Flyweight {
  2. // 一个示意性方法,参数为外绪状态
  3. public void operator(String state);
  4. }

ConcreteFlyweight:

具体的享元实现对象,必须是可共享的,需要封装享元对象的内部状态;内部状态属性应当在享元对象被创建时赋予。所有的内部状态在对象创建后之后,就不会再改变了。如果一个享元对象有外部状态的话。所有的外部状态就必须存储在客户端。在使用享元对象时,再由客户端传入享元对象———-。

  1. public class ConcreteFlyweight implements Flyweight {
  2. private Character internalState = null;
  3. public ConcreteFlyweight(Character state) {
  4. this.internalState = state;
  5. }
  6. /**
  7. * @Description: 外部状态作为参数传入方法中,改变方法的行为,
  8. * 但是不改变对象的内部状态
  9. * @Param: [state]
  10. * @return: void
  11. * @Author: 汪泉
  12. * @Date: 2022/5/9 16:02
  13. **/
  14. @Override--
  15. public void operator(String state) {
  16. System.out.println("externalState:" + state);
  17. System.out.println("internalState:" + this.internalState);
  18. }
  19. }

UnsharedConcreteFlyweight:

非共享的享元实现对象,并不是所有的享元对象都可以共享,非共享的享元对象通常是享元对象的组合对象;

FlyweightFactory:

享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口。不能够通过客户端直接将具体享元类实例化。而必须通过一个工厂对象,利用一个factory()方法得到享元对象。一般来说,工厂对象在整个系统中只有一个,因此也可以使用单例模式。

  1. public class FlyweightFactory {
  2. private Map<Character, Flyweight> files = new HashMap<>();
  3. // Singleton模式
  4. private static FlyweightFactory instance = new FlyweightFactory();
  5. private FlyweightFactory() {
  6. }
  7. public static FlyweightFactory getInstance() {
  8. return instance;
  9. }
  10. public Flyweight factory(Character state) {
  11. // 先从缓存中查找对象
  12. Flyweight flyweight = files.get(state);
  13. if (flyweight == null) {
  14. // 对象不存在则创建一个新的对象
  15. flyweight = new ConcreteFlyweight(state);
  16. // 将创建的对象放入map容器中
  17. files.put(state, flyweight);
  18. }
  19. return flyweight;
  20. }
  21. }

Client:

客户端获取工厂实例,再通过工厂实例获取对象。虽然客户端申请了三个享元对象,但是实际创建的享元对象只有两个,这就是共享的含义。

  1. public class Client {
  2. public static void main(String[] args) {
  3. FlyweightFactory factory =FlyweightFactory.getInstance();
  4. Flyweight fly = factory.factory(new Character('a'));
  5. fly.operator("First Call");
  6. fly= factory.factory(new Character('b'));
  7. fly.operator("Second Call");
  8. fly= factory.factory(new Character('a'));
  9. fly.operator("Third Call");
  10. }
  11. }

复合享元模式:

将一些单纯享元使用组合模式加以组合,可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。