友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

15. 享元模式

15.1. 定义

根据 GoF 的著名著作 《设计模式》,享元模式的定义如下:

享元模式(Flyweight)

运用共享技术有效地支持大量细粒度的对象。

— Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides
《设计模式》

15.2. 类图

Diagram

Flyweight类,它是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。

ConcreteFlyweight是继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。

UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类。因为Flyweight接口共享成为可能,但它并不强制共享。

FlyweightFactory,是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。

尽管我们大部分时间都需要共享对象来降低内存的损耗,但个别时候也有可能不需要共享的,那么此时的UnsharedConcreteFlyweight子类就有存在的必要了,它可以解决那些不需要共享对象的问题。

在享元对象内部并且不会随环境改变而改变的共享部分,可以称为是享元对象的内部状态,而随环境改变而改变的、不可以共享的状态就是外部状态了。事实上,享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。也就是说,享元模式Flyweight执行时所需的状态是有内部的也可能有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。

如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。

用了享元模式,所以有了共享对象,实例总数就大大减少了,如果共享的对象越多,存储节约也就越多,节约量随着共享状态的增多而增大。

实际上在.NET中,字符串string就是运用了Flyweight模式。举个例子吧。Object.ReferenceEquals(object objA,object objB)方法是用来确定objA与objB是否是相同的实例,返回值为bool值

享元模式更多的时候是一种底层的设计模式

在某些情况下,对象的数量可能会太多,从而导致了运行时的资源与性能损耗。那么我们如何去避免大量细粒度的对象,同时又不影响客户程序,是一个值得去思考的问题,享元模式,可以运用共享技术有效地支持大量细粒度的对象。

使用享元模式需要维护一个记录了系统已有的所有享元的列表,而这本身需要耗费资源,另外享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。因此,应当在有足够多的对象实例可供共享时才值得使用享元模式。

代码 93. flyweight/Client.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.diguage.didp.flyweight;

/**
 * Client 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:35
 */
public class Client {
  public static void main(String[] args) {
    int extrinsticState = 22;
    FlyweightFactory factory = new FlyweightFactory();

    FlyWeight fx = factory.getFlyWeight("X");
    fx.operation(--extrinsticState);

    FlyWeight fy = factory.getFlyWeight("Y");
    fy.operation(--extrinsticState);

    FlyWeight fz = factory.getFlyWeight("Z");
    fz.operation(--extrinsticState);

    UnsharedConcreteFlyWeight uf = new UnsharedConcreteFlyWeight();
    uf.operation(--extrinsticState);
  }
}
代码 94. flyweight/ConcreteFlyWeight.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.diguage.didp.flyweight;

/**
 * ConcreteFlyWeight 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-23 09:09:48
 */
public class ConcreteFlyWeight extends FlyWeight {
  @Override
  public void operation(int extrinsticState) {
    System.out.println("具体 FlyWeight:" + extrinsticState);
  }
}
代码 95. flyweight/FlyWeight.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package com.diguage.didp.flyweight;

/**
 * FlyWeight 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-23 09:09:48
 */
public abstract class FlyWeight {
  public abstract void operation(int extrinsticState);
}
代码 96. flyweight/FlyweightFactory.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.diguage.didp.flyweight;

import java.util.HashMap;
import java.util.Map;

/**
 * FlyweightFactory 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:34
 */
public class FlyweightFactory {
  private Map<String, FlyWeight> flyWeights = new HashMap<>();

  public FlyweightFactory() {
    flyWeights.put("X", new ConcreteFlyWeight());
    flyWeights.put("Y", new ConcreteFlyWeight());
    flyWeights.put("Z", new ConcreteFlyWeight());
  }

  public FlyWeight getFlyWeight(String key) {
    return flyWeights.get(key);
  }
}
代码 97. flyweight/UnsharedConcreteFlyWeight.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.diguage.didp.flyweight;

/**
 * UnsharedConcreteFlyWeight 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-23 09:09:48
 */
public class UnsharedConcreteFlyWeight extends FlyWeight {
  @Override
  public void operation(int extrinsticState) {
    System.out.println("不共享的具体 FlyWeight:" + extrinsticState);
  }
}

15.3. 常见示例

  1. java.lang.Integer.valueOf(*)

  2. java.lang.Boolean.valueOf(*)

  3. java.lang.Byte.valueOf(*)

  4. java.lang.Character.valueOf(char c)