第一篇 生成及初始化对象 第七章 - 享元模式

  我们曾提到“对象多样性”的概念,这里以“琵琶曲”为例继续讨论这一话题。
  琵琶音域宽广,简单起见,假设它有4根弦,每根弦有25个发音点位,共可发出 4×25=100 种音。下面使用“音”类描述琵琶的声音。

// 音
public class Yin {

  private int xian;// 1~4,4个弦号。
  private int dian;// 1~25,25个点位。

  public Yin(int xian, int dian) {
    this.xian = xian;
    this.dian = dian;
  }

  public void play() {
    // 大弦嘈嘈如急雨,小弦切切如私语。
  }

}

  为了模拟琵琶的所有声音,我们需要100个对象,它们是:Yin(1,1),Yin(1,2),...,Yin(1,25),...,Yin(4,24),Yin(4,25)。对象多样性之“多”由此可见一斑。
  生成太多的对象难免有浪费之嫌,毕竟内存空间向来宝贵。修改一下“音”类。

// 音
public class Yin {

  private int xian;// 1~4,4个弦号。
  private int dian;// 1~25,25个点位。

  public Yin(int xian) {
    this.xian = xian;
  }

  public void setDian(int dian) {
    this.dian = dian;
  }

  public void play() {}

}

// 测试类
public class Test {

  public void test() {
    Yin obj = new Yin(1);// 生成对象并初始化弦号
    obj.setDian(6);// 设置点位
    obj.play();
    obj.setDian(9);// 弦号不变,点位随机变化。
    obj.play();
  }

}

  此时,我们仅需要4个对象,它们是:Yin(1),Yin(2),Yin(3),Yin(4)。这4个对象分别代表了琵琶的4根弦,模拟声音时,各对象中的弦号保持不变,发音点位随机变化。
  这种有部分成员变量(如弦号)被共享使用的对象称为“享元对象”。使用享元对象可以降低生成的对象数量。
  实践中常将享元对象放到“对象池”中缓存起来以备复用。来看例子。

// 享元对象工厂类
public class YinFactory {

  // 对象池
  private static Map<Integer, Yin> POOL = new HashMap<>();

  public static Yin getYin(Integer i) {
    Yin obj = null;
    if (POOL.containsKey(i)) {
      obj = POOL.get(i);
    } else {
      obj = new Yin(i);
      POOL.put(i, obj);
    }
    return obj;
  }
}

// 测试类
public class Test {

  public void test() {
    Yin obj = YinFactory.getYin(1);// 获取某弦号的对象
    obj.setDian(6);// 设置点位
    obj.play();
    obj.setDian(9);// 点位随机变化
    obj.play();
  }

}
posted on 2025-03-23 14:49  星辰河岳  阅读(32)  评论(0)    收藏  举报