Flyweight概述

Flyweight - 图1

玩具代码案例 - 字体享元管理器

享元对象

同一种类型的字体没有必要频繁创建,完全可以重复使用

  1. package online.javabook.gof.structural.patterns6.flyweight.font;
  2. import java.util.Objects;
  3. public class Font {
  4. final String name;
  5. final int style;
  6. final int size;
  7. public Font(String name, int style, int size) {
  8. this.name = name;
  9. this.style = style;
  10. this.size = size;
  11. }
  12. @Override
  13. public boolean equals(Object o) {
  14. if (this == o) return true;
  15. if (o == null || getClass() != o.getClass()) return false;
  16. Font font = (Font) o;
  17. return style == font.style &&
  18. size == font.size &&
  19. Objects.equals(name, font.name);
  20. }
  21. @Override
  22. public int hashCode() {
  23. return Objects.hash(name, style, size);
  24. }
  25. }
  1. package online.javabook.gof.structural.patterns6.flyweight.font;
  2. public interface Style {
  3. final static int PLAIN = 1;
  4. final static int BOLD = 2;
  5. final static int ITALIC = 3;
  6. }

享元对象管理器

  1. package online.javabook.design.gof.structural6.flyweight.font;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. import java.util.concurrent.ConcurrentMap;
  6. public class FontFlyweight {
  7. private static ConcurrentMap<String, Font> flyweights = new ConcurrentHashMap<>();
  8. public static Font create(String name, int style, int size) {
  9. Font font = null;
  10. if(!flyweights.containsKey(name)) {
  11. font = flyweights.putIfAbsent(name, new Font(name, style, size));
  12. }
  13. return font;
  14. }
  15. }

不基于享元模式的实现

Main

  1. package online.javabook.gof.structural.patterns6.flyweight.font.app.bad;
  2. import online.javabook.gof.structural.patterns6.flyweight.font.Font;
  3. import online.javabook.gof.structural.patterns6.flyweight.font.Style;
  4. public class Main {
  5. public static void main(String[] args) {
  6. Font font1 = new Font("宋体", Style.BOLD, 12);
  7. Font font2 = new Font("宋体", Style.BOLD, 12);
  8. System.out.println("font1 == font2 ? " + (font1 == font2));
  9. }
  10. }

Console

  1. font1 == font2 ? false

基于享元模式的实现

Main

package online.javabook.gof.structural.patterns6.flyweight.font.app.good;

import online.javabook.gof.structural.patterns6.flyweight.font.Font;
import online.javabook.gof.structural.patterns6.flyweight.font.FontFlyweight;
import online.javabook.gof.structural.patterns6.flyweight.font.Style;

public class Main {
    public static void main(String[] args) {

        Font font1 = FontFlyweight.create("宋体", Style.BOLD, 12);
        Font font2 = FontFlyweight.create("宋体", Style.BOLD, 12);

        System.out.println("font1 == font2 ? " + (font1 == font2));
    }
}

Console

font1 == font2 ? true

现实世界中的享元模式

字符集对象

没有必要每次都生成一个字符集对象

package online.javabook.io.bio.charset;

import java.nio.charset.Charset;

public class CharsetMain {
    public static void main(String[] args) {

        //返回指定的字符集CharSet
        Charset utf81 = Charset.forName("utf8");

        //返回指定的字符集CharSet
        Charset utf82 = Charset.forName("utf8");

        System.out.println(utf81 == utf82);
    }
}

Console

true

字符串对象

Java字符串对象的常量池我认为也是一种享元模式。字符串在开发者被频繁创建,相同的字符串如果能够重用,自然是能够降低内存的使用。

只是大家关注的都是string创建了几个对象,引用比较,放在永生区还是堆中等等这些问题上。而不是真正学习设计的本身,本末倒置。

    /**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     */
    public native String intern();