zoukankan      html  css  js  c++  java
  • 结构型模式之享元

    享元(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与模式》

     

  • 相关阅读:
    第十四周 Leetcode 315. Count of Smaller Numbers After Self(HARD) 主席树
    POJ1050 To the Max 最大子矩阵
    POJ1259 The Picnic 最大空凸包问题 DP
    POJ 3734 Blocks 矩阵递推
    POJ2686 Traveling by Stagecoach 状态压缩DP
    iOS上架ipa上传问题那些事
    深入浅出iOS事件机制
    iOS如何跳到系统设置里的各种设置界面
    坑爹的私有API
    业务层网络请求封装
  • 原文地址:https://www.cnblogs.com/codeMedita/p/7358053.html
Copyright © 2011-2022 走看看