• 结构型模式之享元


    享元(Flyweight)模式是有关改善性能的一种方法,GOF对享元的功能定义是:运用共享技术有效地支持大量细粒度的对象。为了做到共享,首先要区分内部状态(Internal State)和外部状态(External State)。内部状态是存储在享元对象的内部,不随环境的变化而有所不同,因而可以共享这些享元;外部状态是随环境改变而变化的,不可共享的状态。GOF一书中举了一个例子:文档编辑器问题,一个编辑器通常提供多种格式的字体,每一个字符都是作为一个对象嵌入到编辑器中,这时候如果把特定的格式和特定的字符关联起来,则需要创建很多对象,显然功能复用设计要求相违背;这时候可以将每个字符做成一个享元对象,享元的内部状态就是这个字符本身,外部状态则是字符位置、风格等外在表现形式。如文档中可能出现字符a,虽然a的位置和风格可能不同,但是使用的都是同一个字符对象,这样这个a字符对象就可以在整个系统中共享,而不是每一处都创建一个a字符对象。享元模式的结构如下:

    这其中有一个UnsharedConcreteFlyweight类,它是复合享元角色,不可共享,复合享元对象可以分解成多个本身是享元对象的组合。

    现在给出一个示例代码,这段代码取自于《Thinking In Patterns》,考虑一个 DataPoint 对象,它包含一个 int 和 float类型的数据成员,还有一个 id 数据成员用来表示对象编号。假设你需要创建一百万个这样的对象,然后对它们进行操作,像下面这样:

     1 class DataPoint {
     2     private static int count = 0;
     3     private int id = count++;
     4     private int i;
     5     private float f;
     6     public int getI() { return i; }
     7     public void setI(int i) { this.i = i; }
     8     public float getF() { return f; }
     9     public void setF(float f) { this.f = f; }
    10     public String toString() {
    11         return "id: " + id + ", i = " + i + ", f = " + f;
    12     }
    13 }
    14 
    15 public class Test{
    16     static final int size = 1000000;
    17     public static void main(String[] args) {
    18     DataPoint[] array = new DataPoint[size];
    19     for(int i = 0; i < array.length; i++)
    20     array[i] = new DataPoint();
    21     for(int i = 0; i < array.length; i++) {        
    22         DataPoint dp = array[i];
    23             dp.setI(dp.getI() + 1);
    24             dp.setF(47.0f);
    25         }
    26         System.out.println(array[size -1]);
    27     }
    28 }
    View Code

    测试运行,估计需要运行很长时间。仔细分析,发现可以将int和float数据外化出去,并且提供对这些数据的操作方法,没必要将每一对int和float的数据存储到一个对象中,完全可以将这些数据存储到一个类中,该类提供对这些数据的操作,这样只需要创建一个对象就可以满足需求了。如下所示:

     1 class ExternalizedData {
     2     static final int size = 5000000;
     3     static int[] id = new int[size];
     4     static int[] i = new int[size];
     5     static float[] f = new float[size];
     6     static {
     7     for(int i = 0; i < size; i++)
     8     id[i] = i;
     9     }
    10 }
    11 class FlyPoint {
    12     private FlyPoint() {}
    13     public static int getI(int obnum) {
    14         return ExternalizedData.i[obnum];
    15     }
    16     public static void setI(int obnum, int i) {
    17         ExternalizedData.i[obnum] = i;
    18     }
    19     public static float getF(int obnum) {
    20         return ExternalizedData.f[obnum];
    21     }
    22     public static void setF(int obnum, float f) {
    23         ExternalizedData.f[obnum] = f;
    24     }
    25     public static String str(int obnum) {
    26         return "id: " +
    27         ExternalizedData.id[obnum] +
    28         ", i = " +
    29         ExternalizedData.i[obnum] +
    30         ", f = " +
    31         ExternalizedData.f[obnum];
    32     }
    33 }
    34     
    35 public class Test{
    36     public static void main(String[] args) {
    37         for(int i = 0; i < ExternalizedData.size; i++) {
    38             FlyPoint.setI(i, FlyPoint.getI(i) + 1);
    39             FlyPoint.setF(i, 47.0f);
    40         }
    41         System.out.println(FlyPoint.str(ExternalizedData.size -1));
    42     }
    43 }
    View Code

    这里,FlyPoint就是一个享元,不同int和float对值相当于FlyPoint的表现形式,相当于加粗和不加粗的A字母一样,我们将加粗和不加粗这两种表现形式放到一起,与字符A分开,不同的表现形式作用于同一个字母A是展现不同的效果,这样我们就不用创建一个加粗的A字符,需要的时候又创建一个不加粗的A字符,这样创建了两个字符对象,显然如果篇幅较大的话,可能创建很多的A字符,而通过享元模式,则通篇就可以只创建一个A字符!

    时间原因,没有自己设计代码,以上内容参考自《Thinking in Patterns》、GOF一书、《Java与模式》

     

  • 相关阅读:
    windows8 Metro icon
    JPG高度压缩的图像格式
    windows RT Xamltoolkit
    爸爸和无我编程(Egoless Programming)十条诫律 (转)
    内存优化文章链接
    在 windows 8 下打开字符映射表
    在 windows 8 下安装 windows phone 7.1 SDK 和 zune
    异步线程返回 UI 线程
    工厂模式
    jquery预览本地图片
  • 原文地址:https://www.cnblogs.com/codeMedita/p/7358053.html
Copyright © 2020-2023  润新知